1.1 索引基礎
簡單講,索引就是書籍后面的“索引”-Index,幫助我們找到特定主題、詞語,然后告訴我們具體對應的頁碼。在MySQL中存儲引擎用類似的方法使用索引,先在索引中找到對應的值,然后根據匹配的索引記錄找到對應的數據行。
簡單例子: select name from actor where actor_id=5; 前提:actor_id 列上建有索引。MySQL 將使用在該列上創建的索引找到 actor_id 為 5 的行,按值在索引上查找,然后返回包含該值(5)的數據行。
像上面的例子,一般可能直接被認為 actor 表以 actor_id 一個列為索引,但正如大多數人做的那樣,一個表的索引可能還會包含一個以上的列(多個列)的值。如果是多個列,那么順序很重要,因為MySQL只能高效利用 最左前綴列。另外,創建一個包含兩個列的索引,和創建兩個只包含一個列的索引是大不相同的,未來解釋。
無論多么復雜的ORM工具,在精妙和復雜的索引面前都是浮云!
索引有很多類型,索引在存儲引擎層實現,不在服務器層,因此不同存儲引擎、不同索引類型的底層實現都不相同。基本類型包括B-Tree索引、哈希索引、空間數據索引(R-Tree)、全文索引等。
====================B-Tree索引==============
上面的表中,姓(last_name)、名(first_name)、出生日期(dob)為索引(key),圖上為這三個列組成的索引的數據組織形式,其中 last_name (姓)是最左前綴,參考鏈接《最左前綴原則(博文)》
B-Tree索引適用于全值匹配(索引中所有列匹配,Allen、Cuba、1960-01-01)、匹配最左前綴(索引的前綴列,只使用索引第一列,姓 Allen)、匹配列前綴(索引列的前綴,姓列前綴,查 All開頭的姓)、匹配范圍值(查找 A字母~B字母開頭的姓)、精確匹配某一列并范圍匹配另外一列(姓列精確匹配=Allen,名稱列范圍,以K字母開頭的名)、只訪問索引的查詢(不訪問數據行,叫“覆蓋索引”,未來解釋)。
B-Tree以上查找原則,也使用于 ORDER BY 排序字段,能查找就能排序。
B-Tree有些傻乎乎,像人一樣固執得狠!不能跳過最左前綴(last_name),只查滿足名字和生日的不行;也不能跳過中間列,只查滿足姓和生日的不行;如果中間列有范圍查詢,則居其右邊的列優化用不上,例如:WHERE last_name='Smith' AND first_name LIKE 'J%' dob='1976-12-23',dob的優化用不上,因為 first_name 是個范圍查詢。
由上可以看出 B-Tree索引列的順序多么多么的重要,在優化時,需要創建相同的多個列但順序不同的索引,來滿足不同的需求,如:key1(last_name, first_name, dob),key1(first_name,last_name,dob),key1(dob,first_name,last_name)
==================== 哈希索引==============
哈希索引,僅用于精確匹配,僅存在于Memory引擎,每行數據都計算一個哈希碼(hash code),MySQL接收查詢命令后,如:select last_name from People where first_name='Peter' ,先計算 Peter 的哈希值,然后用該哈希值找到記錄數據行的指針,通過指針找到數據行,然后判斷找到的數據是否為Peter,如果是返回數據。
哈希索引,特點結構緊湊,速度快。
偽哈希索引,因為哈希索引只在 Memory中存在,所以可以參考書中自行在其他引擎中創建偽哈希索引,效果不錯,但注意哈希值沖突的解決。
====================空間數據索引(R-Tree)==============
MyISAM支持空間數據索引,可以用作地理數據存儲。但MySQL做得不好,很少使用。
====================?全文索引==============
全文索引,查找的是文本中的關鍵詞,而不是直接比較索引中的值,與其他索引完全不同,不是簡單的 WHERE 匹配,而更像搜索引擎做的事情,適用于 MATCH AGAINST 操作。
全文索引,詳細見第七章。
===========================================================
1.2 索引優點
索引優點,大大減少了服務器需要掃描的數據量(快速定位);
索引優點,可以幫助服務器避免排序和臨時表(順序存儲,便于ORDER BY、GROUP BY);
索引優點,將隨機I/O,變為順序I/O。
索引辯證法,小表,全表掃描更高效;中大表,索引高效;超大表,索引代價高,可以使用分區技術,見第7章。
===========================================================
1.3 高性能索引策略
1)將索引列要獨立,放在比較符號的一側,例如 select * from actor where actor_id + 1 = 5; 應寫為 select * from actor where actor_id = 4;
2)前綴索引,一般對BLOB、TEXT、很長的VARCHAR使用,需要保證索引的選擇性要高,就是索引的值的數量和記錄的總數盡量持平,一般的自增id作為索引基本上選擇性=1,不會重復。使用前綴索引要先預估選擇性的值,書中有實例。
3)多列索引,在多個列上單獨建立索引多數情況下不能提高效率,特別對于AND、OR操作,OR操作更浪費。
4)選擇合適的索引列順序,將選擇性最高的列放最左,但只是經驗做法。
5) 聚簇索引
6)覆蓋索引
7)使用索引掃描來做排序!(很重要!!!)
MySQL通過兩種方式生成有序結果:通過排序操作,或,按索引順序掃描。當 Explain的結果中 type 為 index,就說明MySQL用了索引掃描來做排序了!
掃描索引是很快了的,但如果索引沒有能覆蓋查詢中所需的全部列,那就不得不每掃描一條索引記錄就回表查詢一次對應的行(自問:為什么?:-))這基本就是隨機I/O了,慢,慢!
設計時,一定要注意,如果有一條索引(可能多個列),既能滿足查找,又能滿足排序,那就好了。