/* * -------------------------------------------------------- * 高性能MySQL-3rd-Baron Schwartz-筆記 * 第五章 建立高性能的索引 */ --------------------------------------------------------
5.1 索引基礎
html
簡單講,索引就是書籍後面的「索引」-Index,幫助咱們找到特定主題、詞語,而後告訴咱們具體對應的頁碼。在MySQL中存儲引擎用相似的方法使用索引,先在索引中找到對應的值,而後根據匹配的索引記錄找到對應的數據行。java
簡單例子: select name from actor where actor_id=5; 前提:actor_id 列上建有索引。MySQL 將使用在該列上建立的索引找到 actor_id 爲 5 的行,按值在索引上查找,而後返回包含該值(5)的數據行。mysql
像上面的例子,通常可能直接被認爲 actor 表以 actor_id 一個列爲索引,但正如大多數人作的那樣,一個表的索引可能還會包含一個以上的列(多個列)的值。若是是多個列,那麼順序很重要,由於MySQL只能高效利用 最左前綴列。另外,建立一個包含兩個列的索引,和建立兩個只包含一個列的索引是大不相同的,將來解釋。sql
不管多麼複雜的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 排序字段,能查找就能排序。spa
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 操做。
全文索引,詳細見第七章。
===========================================================
5.2 索引優勢
索引優勢,大大減小了服務器須要掃描的數據量(快速定位);
索引優勢,能夠幫助服務器避免排序和臨時表(順序存儲,便於ORDER BY、GROUP BY);
索引優勢,將隨機I/O,變爲順序I/O。
索引辯證法,小表,全表掃描更高效;中大表,索引高效;超大表,索引代價高,可使用分區技術,見第7章。
===========================================================
5.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了,慢,慢!
設計時,必定要注意,若是有一條索引(可能多個列),既能知足查找,又能知足排序,那就行了。
參考資料:mysql explain