使用索引的目的
使用索引的目的是提高數據庫查詢的效率。索引是怎么提高數據庫查詢的效率的呢?舉個通俗的例子,查字典。數據庫中的數據就好比新華字典中的詞條,索引就是新華字典的目錄。沒有建立索引的數據庫就好像被撕掉目錄的新華字典,只能從頭到尾一條一條地查詢,效率極其低下。
為了能更快地查字典,哦不,是查詢數據庫,我們就需要為數據庫建立索引。
索引的原理
索引的主要思想是將數據分段,從而減少查詢時的無效數據,提高查詢效率。比如有1000條數據,1到100分成第一段,101到200分成第二段,201到300分成第三段……這樣查第250條數據,只要找第三段就可以了,一下子去除了90%的無效數據。
當然,上面只是主要思想,MySQL使用了更加具體的數據結構來實現索引。本文不對索引的數據結構展開討論。
建立索引的幾大原則
如何建立合適的索引,從而最大程度地優化查詢效率是一件需要精心設計的事情。本節只介紹幾個建立索引時須遵循的原則。
- 最左前綴匹配原則,非常重要的原則。mysql會一直向右匹配直到遇到范圍查詢
>
、<
、between
、like
就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4
如果建立(a,b,c,d)
順序的索引,d是用不到索引的,如果建立(a,b,d,c)
的索引則都可以用到,a,b,d的順序可以任意調整。關于最左前綴匹配原則,在最左前綴匹配原則一節有詳細說明。 - 盡量選擇區分度高的列作為索引,區分度公式為
count(distinct col)/count(*)
,即一列中內容不同的記錄數占總記錄數的比例。通過這個公式我們可以得到字段不重復的比例,比例越大我們掃描的記錄數越少,唯一鍵的區分度是1,而一些狀態、性別字段可能在大數據面前區分度就是0。所以唯一索引的效率是最高的。在不是唯一鍵的時候,就要具體情況具體分析了,這也是索引設計的關鍵點之一。 - 索引列不能參與計算,保持列“干凈”,比如
from_unixtime(create_time) = ’2014-05-29’
就不能使用到索引,原因很簡單,索引的數據結構中存的都是數據表中的字段值,但進行檢索時,需要把所有元素都應用函數才能比較,顯然成本太大。所以語句應該寫成create_time = unix_timestamp(’2014-05-29’)
; - 盡量的擴展索引,不要新建索引。比如表中已經有a的索引,現在要加(a,b)的索引,那么只需要修改原來的索引即可
- 使用短索引。如果對串列進行索引,應該指定一個前綴長度,只要有可能就應該這樣做 。
例如,如果有一個 CHAR(200) 列,如果在前 10 個或 20 個字符內,多數值是惟一的,
那么就不要對整個列進行索引。對前 10 個或 20 個字符進行索引能夠節省大量索引空
間,也可能會使查詢更快。
最左前綴匹配原則
最左前綴使用場景是使用復合索引的時候。當使用復合索引時,如果想要索引有效,where
之后的表達式就要滿足最左前綴匹配原則。
我總結了一下最左前綴匹配的特點,就是從表達式最左邊開始,到第一個范圍查詢結束,在這個閉區間內的字段應該是索引字段的最左前綴。
最左前綴
在這里解釋一下最左前綴,因為沒有百度到感覺比較靠譜的解釋,所以我在這里談一下我的理解,僅供參考。
前綴應該不用解釋了,學過英語的都該懂點。前綴加個左就是左前綴了,表示從左邊開始查找的前綴。但是,這個左只是表示查找的順序是從左邊開始,不是從右邊開始,并沒有說從哪一位開始,可能是第一位,也可能是第三位。這時候再加一個 最 就表示了從最左邊開始。
比如復合索引是(a,b,d,c),那么查詢時表達式的字段順序為(a)、(a,b)、(a,b,d)、(a,b,d,c)的這些都是它的最左前綴,而(b)、(a,d)、(a,b,c)、(a,b,c,d)這些就不是。
關于MySQL的查詢優化器
最左前綴的概念我們已經明白了,但是在MySQL中的情況又有點不同。比如我們發現,索引的順序是(a,b,d,c),我們的查詢條件是這樣寫的:where b=10 and c=16 and a=26 and d=0
,從嚴格意義上來講,這個順序是不符合最左前綴匹配原則的,但是MySQL的確使用索引完成了查詢。這是怎么回事呢?這是因為MySQL的查詢優化器幫我們調整了查詢條件的順序。MySQL查詢優化器會判斷糾正一條sql語句該以什么樣的順序執行效率最高,最后才生成真正的執行計劃。在有索引的情況下當然是利用索引查詢順序的效率最高咯,所以,MySQL查詢優化器會最終以索引的順序進行查詢執行。
最左前綴匹配原則的原理
上面說了這么多的最左前綴的概念,那么我們到底為什么一定要符合最左前綴匹配原則呢?
因為復合索引只有第一個字段是絕對有序的,從第二個開始的字段都只是相對前一個字段有序,在全局范圍內是無序的。只有滿足最左前綴原則,才可以保證查詢內容的有序,而有序又是索引使用的前提。
我們來看個例子,以該表的(name,cid)復合索引為例,它內部結構簡單說就是下面這樣排列的:
name | cid |
---|---|
a | 6 |
c | 4 |
c | 5 |
h | 1 |
z | 9 |
MySQL創建復合索引的規則是首先會對復合索引的最左邊的,也就是第一個name
字段的數據進行排序,在第一個字段的排序基礎上,然后再對后面第二個的cid
字段進行排序。其實就相當于實現了類似 order by name cid
這樣一種排序規則。
第一個name字段是絕對有序的,而第二字段就是無序的了。所以通常情況下,直接使用第二個cid
字段進行條件判斷是用不到索引的。
那么什么時候才能用到呢?當然是cid
字段的索引數據也是有序的情況下才能使用咯,什么時候才是有序的呢?觀察可知,當然是在name
字段是等值匹配的情況下,cid
才是有序的。發現沒有,觀察兩個name
名字為 c
的cid
字段是不是有序的呢。從上往下分別是4
5
。這也就是MySQL索引規則中要求復合索引要想使用第二個索引,必須先使用第一個索引的原因(最左前綴匹配原則)。
補充使用索引時的具體情況
更多使用索引的詳細情況,可以參考最左前綴原理與相關優化
本文的參考資料
http://blog.jobbole.com/86594/