mysql索引以及優化

来源:http://www.cnblogs.com/mantianxing/archive/2017/08/01/7270052.html
-Advertisement-
Play Games

今天看到別人寫的一些關於mysql索引的文章,有一些小收穫,就以此開啟我的隨筆記錄簡單摘了一些重點 轉載文章:http://www.cnblogs.com/tgycoder/p/5410057.html mysql索引實現原理 1. MyISAM引擎使用B+Tree作為索引結構,葉結點的data域存 ...


今天看到別人寫的一些關於mysql索引的文章,有一些小收穫,就以此開啟我的隨筆記錄簡單摘了一些重點

轉載文章:http://www.cnblogs.com/tgycoder/p/5410057.html

mysql索引實現原理

    1. MyISAM引擎使用B+Tree作為索引結構,葉結點的data域存放的是數據記錄的地址,MyISAM的索引方式也叫做“非聚集”的,之所以這麼稱呼是為了與InnoDB的聚集索引區分。

  

 2. InnoDB也使用B+Tree作為索引結構,第一個重大區別是InnoDB的數據文件本身就是索引文件,第一個重大區別是InnoDB的數據文件本身就是索引文件。從上文知道,MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。而在InnoDB中,表數據文件本身就是按B+Tree組織的一個索引結構,這棵樹的葉結點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,因此InnoDB表數據文件本身就是主索引

  

InnoDB主索引(同時也是數據文件)的示意圖,可以看到葉結點包含了完整的數據記錄。這種索引叫做聚集索引。因為InnoDB的數據文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則MySQL系統會自動選擇一個可以唯一標識數據記錄的列作為主鍵,如果不存在這種列,則MySQL自動為InnoDB表生成一個隱含欄位作為主鍵,這個欄位長度為6個位元組,類型為長整形。

3. 最左首碼與相關優化

    之前我理解的最左首碼以為索引的順序是跟where條件查詢的一致不一致就使用不到索引,這是錯誤的

  Ps:最左首碼原則中where字句有or出現還是會遍歷全表

   (1) 其實where條件的順序不影響使用索引,比如三個欄位添加聯合索引t_user表聯合索引(name, mobile, create_date)

     select * from t_user where mobile = '13256767876' and create_date= '2017-07-31' and name = 'corner';

      理論上索引對順序是敏感的,但是由於MySQL的查詢優化器會自動調整where子句的條件順序以使用適合的索引,所以這樣也是可以用到索引的

    (2)查詢條件沒有指定索引第一列

   如果where條件中沒有name條件,只有另外兩個無論順序是什麼都是無法用到索引的,如果where條件只有name,status而沒有mobile這時候只能用到一列索引,status這一列的索引是用不到的

     (3)範圍查詢

             範圍列可以用到索引(必須是最左首碼),但是範圍列後面的列無法用到索引。同時,索引最多用於一個範圍列,因此如果查詢條件中有兩個範圍列則無法全用到索引

             表t_title聯合索引(emp_no,title,from_date)

EXPLAIN SELECT * FROM employees.titles
WHERE emp_no < '10010'
AND title='Senior Engineer'
AND from_date BETWEEN '1986-01-01' AND '1986-12-31';
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | titles | range | PRIMARY       | PRIMARY | 4       | NULL |   16 | Using where |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
  只能用到第一列索引,這裡特別要說明MySQL一個有意思的地方,那就是僅用explain可能無法區分範圍索引和多值匹配,因為在type中這兩者都顯示為range。同時,用了“between”並不意味著就是範圍查詢,例如下麵的查詢:
全部索引都用到了
EXPLAIN SELECT * FROM employees.titles
WHERE emp_no BETWEEN '10001' AND '10010'
AND title='Senior Engineer'
AND from_date BETWEEN '1986-01-01' AND '1986-12-31';
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | titles | range | PRIMARY       | PRIMARY | 59      | NULL |   16 | Using where |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
(4)查詢條件中含有函數或表達式
如果查詢條件中含有函數或表達式,則MySQL不會為這列使用索引
like如果通配符%不出現在開頭,則可以用到索引,但根據具體情況不同可能只會用其中一個首碼
EXPLAIN SELECT * FROM employees.titles WHERE emp_no='10001' AND title LIKE 'Senior%';
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | titles | range | PRIMARY       | PRIMARY | 56      | NULL |    1 | Using where |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+

4.索引選擇性與首碼索引
 (1)什麼情況下判斷欄位是否應該建立索引,今天剛看到這個"選擇性"的概念,除了表數據很少的情況不用建索引因為索引文件本身要消耗存儲空間會加重資料庫操作的負擔,另外一種情況就是索引的選擇性比較低:
所謂索引的選擇性(Selectivity),是指不重覆的索引值(也叫基數,Cardinality)與表記錄數(#T)的比值:Index Selectivity = Cardinality / #T
顯然選擇性的取值範圍為(0, 1],選擇性越高的索引價值越大,這是由B+Tree的性質決定的。

           這個問題就像是面試時提問我的一個問題:性別列適不適合建立索引?(答案是否定的)


           例如,上文用到的employees.titles表,如果title欄位經常被單獨查詢,是否需要建索引,我們看一下它的選擇性:



SELECT count(DISTINCT(title))/count(*) AS Selectivity FROM employees.titles;
+-------------+
| Selectivity |
+-------------+
|      0.0000 |
+-------------+

title的選擇性不足0.0001(精確值為0.00001579),所以實在沒有什麼必要為其單獨建索引。


  (2)有一種與索引選擇性有關的索引優化策略叫做首碼索引,就是用列的首碼代替整個列作為索引key,當首碼長度合適時,可以做到既使得首碼索引的選擇性接近全列索引,同時因為索引key變短而減少了索引文件的大小和維護開銷。下麵以employees.employees表為例介紹首碼索引的選擇和使用。

從圖12可以看到employees表只有一個索引<emp_no>,那麼如果我們想按名字搜索一個人,就只能全表掃描了:

EXPLAIN SELECT * FROM employees.employees WHERE first_name='Eric' AND last_name='Anido';
+----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 300024 | Using where |
+----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+

如果頻繁按名字搜索員工,這樣顯然效率很低,因此我們可以考慮建索引。有兩種選擇,建<first_name>或<first_name, last_name>,看下兩個索引的選擇性:

複製代碼
SELECT count(DISTINCT(first_name))/count(*) AS Selectivity FROM employees.employees;
+-------------+
| Selectivity |
+-------------+
|      0.0042 |
+-------------+
SELECT count(DISTINCT(concat(first_name, last_name)))/count(*) AS Selectivity FROM employees.employees;
+-------------+
| Selectivity |
+-------------+
|      0.9313 |
+-------------+
複製代碼

<first_name>顯然選擇性太低,<first_name, last_name>選擇性很好,但是first_name和last_name加起來長度為30,有沒有兼顧長度和選擇性的辦法?可以考慮用first_name和last_name的前幾個字元建立索引,例如<first_name, left(last_name, 3)>,看看其選擇性:

SELECT count(DISTINCT(concat(first_name, left(last_name, 3))))/count(*) AS Selectivity FROM employees.employees;
+-------------+
| Selectivity |
+-------------+
|      0.7879 |
+-------------+

選擇性還不錯,但離0.9313還是有點距離,那麼把last_name首碼加到4:

SELECT count(DISTINCT(concat(first_name, left(last_name, 4))))/count(*) AS Selectivity FROM employees.employees;
+-------------+
| Selectivity |
+-------------+
|      0.9007 |
+-------------+

這時選擇性已經很理想了,而這個索引的長度只有18,比<first_name, last_name>短了接近一半,我們把這個首碼索引 建上:

ALTER TABLE employees.employees
ADD INDEX first_name_last_name4 (first_name, last_name(4));

此時再執行一遍按名字查詢,比較分析一下與建索引前的結果:

複製代碼
SHOW PROFILES;
+----------+------------+---------------------------------------------------------------------------------+
| Query_ID | Duration   | Query                                                                           |
+----------+------------+---------------------------------------------------------------------------------+
|       87 | 0.11941700 | SELECT * FROM employees.employees WHERE first_name='Eric' AND last_name='Anido' |
|       90 | 0.00092400 | SELECT * FROM employees.employees WHERE first_name='Eric' AND last_name='Anido' |
+----------+------------+---------------------------------------------------------------------------------+
複製代碼

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一,代碼。 二,輸出。 ...
  • [20170728]oracle保留字.txt--//oracle有許多保留字,我印象最深的就是使用rman備份表空間test,test就是rman裡面的保留字.--//還有rman也是rman裡面的保留字.如果在應用中儘量規避不要使用這些保留字.--//探究一下,oracle內部是否也會不小心這些 ...
  • 作者: kent鵬 轉載請註明出處: http://www.cnblogs.com/xieyupeng/p/7272236.html Oracle的集群 Oracle的體繫結構 SQL> --當前用戶 SQL> show user USER 為 "SCOTT" SQL> --當前用戶下的表 SQL> ...
  • 原文地址:http://blogxinxiucan.sh1.newtouch.com/2017/08/01/Java-curator%E6%93%8D%E4%BD%9Czookeeper%E8%8E%B7%E5%8F%96kafka/ Curator是Netflix公司開源的一個Zookeeper... ...
  • 目錄 · 概況 · 手工搭建集群 · 引言 · 安裝Scala · 配置文件 · 啟動與測試 · 應用部署 · 部署架構 · 應用程式部署 · 核心原理 · RDD概念 · RDD核心組成 · RDD依賴關係 · DAG圖 · RDD故障恢復機制 · Standalone模式的S ...
  • 在不同地域的兩個SQL Server伺服器上配置了複製(Replication)用於同步數據(生產環境配置有Replication,測試環境也配有Replication),兩地通過專線連接起來,這些複製(Replication)已經穩定運行了一兩年了, 但是前陣子,測試環境的SQL Server的R... ...
  • 接上篇博客,寫完以後看了看,還是覺的寫的太簡單,就算是自己複習都不夠,所以再補充一些 1.創建多表關聯 需求:圖書管理系統,創建幾張表,包含書籍,出版社,作者,作者詳細信息等內容 分析: (1)圖書只有一個出版社,出版社可以出版很多書,多對一關係 (2)圖書可以有多個作者,一個作者也可以寫多本書,多 ...
  • 平常經常會求一段時間內的每一天統計數據,或者每一時點的統計數據。但是mysql本身是沒有直接獲取時點列表的函數或表。下麵是自己用到的一些方法,利用臨時變數和一個已存在的比較多數據(這個需要根據實際情況決定)的表做關聯得到時點列表。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...