高性能索引
什么是索引
索引是存儲(chǔ)引擎用于快速找到記錄的一種數(shù)據(jù)結(jié)構(gòu)。索引工作流程
如果想在一本書(shū)中找到某個(gè)特定主體,一般會(huì)先看書(shū)的“索引”,然后找到對(duì)應(yīng)的頁(yè)碼。在MYSQL中,存儲(chǔ)引擎用類似的方法使用索引,先在索引中找到對(duì)應(yīng)值,然后根據(jù)匹配的索引記錄找到對(duì)應(yīng)的數(shù)據(jù)行。例如:要查找user_id = 2 的 用戶信息,其中在user_id上建有索引: SELECT name,age FROM user WHERE user_id = 2; 則MYSQL先在索引上按值進(jìn)行查找到 user_id = 2的行,然后返回所有包含該值的數(shù)據(jù)行。 索引可以包含一個(gè)或者多個(gè)列的值。如果索引包含多個(gè)列,那么索引只能高效的使用索引的最左前綴列。索引類型和實(shí)現(xiàn)原理
索引類型
- B-Tree索引
- 哈希索引
- 空間數(shù)據(jù)索引
- 全文索引
B-Tree索引
B-Tree索引底層使用B-Tree數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)數(shù)據(jù)。索引定義中提到索引是一種快速找到記錄的數(shù)據(jù)結(jié)構(gòu)。那么為什么這種數(shù)據(jù)結(jié)構(gòu)能夠快速找到記錄呢?先來(lái)了解一下B-Tree數(shù)據(jù)結(jié)構(gòu)。 B-Tree (B+Tree)又叫平衡多路查找樹(shù)。從名字可以看到:- 首先它是一棵查找樹(shù),左子樹(shù)上所有結(jié)點(diǎn)的值均小于它的根結(jié)點(diǎn)的值,右子樹(shù)上所有的節(jié)點(diǎn)的值均大于它的根節(jié)點(diǎn)的值。(二叉)
- 其次它是一棵平衡樹(shù),保證樹(shù)的深度由各個(gè)子節(jié)點(diǎn)均攤
- 最后它是多路,每層有多個(gè)節(jié)點(diǎn)分支,減少訪問(wèn)深度,減少磁盤(pán)I/O次數(shù)
- 葉子節(jié)點(diǎn)的指針指向的是被索引的數(shù)據(jù),而不是其他的節(jié)點(diǎn)頁(yè)
- InnoDB 的邏輯頁(yè)/數(shù)據(jù)頁(yè) 16K的含義:這和盤(pán)塊 大小有關(guān)。位于同一盤(pán)塊的數(shù)據(jù)可以一次讀取出來(lái),設(shè)置成盤(pán)塊的整數(shù)倍這樣可以減少磁道查找時(shí)間。而且可以減少I/O次數(shù)。(待討論)
?
其中需要注意的點(diǎn):索引對(duì)多個(gè)值進(jìn)行排序的依據(jù)是CREATE TABLE 語(yǔ)句中定義索引列的順序。為什么呢?因?yàn)樗饕龢?shù)在建立后插入的順序就是根據(jù)此規(guī)則插入的。順序也就是:KEY(last_name,first_name,dob)
依據(jù)上述例子,可以用到B-Tree索引的查詢有:全鍵值、鍵值范圍或鍵前綴查找(最左前綴)。具體如下:全值匹配(和索引中的所有列進(jìn)行匹配):
查找姓名為Cuba Allen、出生于1960-01-01的人匹配最左前綴:
查找所有姓為Allen的人匹配列前綴:
查找所有以J開(kāi)頭的姓的人匹配范圍值:
查找姓在Allen和Barry之間的人精確匹配某一列并范圍匹配另外一列:
查找所有姓為Allen,并且名字是字母與K開(kāi)頭的人只訪問(wèn)索引的查詢
總結(jié)來(lái)說(shuō)也就是三種情況:1、就是索引全部用到了2、就是索引部分用到,且符合最左匹配原則3、就是使用索引的范圍查詢。(注意:如果查詢中有某個(gè)列的范圍查詢,那么這個(gè)列右邊的所有列(不包括該范圍列)都無(wú)法使用索引優(yōu)化查找。其中:LIKE 屬于范圍查找)索引好處
索引可以讓服務(wù)器快速的定位到表的指定位置。從而可以提升查詢速度。 對(duì)于最常見(jiàn)的B-Tree索引,因?yàn)榇鎯?chǔ)數(shù)據(jù)是順序的,所以MYSQL可以用來(lái)做ORDER BY和GROUP BY操作。(使用索引掃描來(lái)做排序)。因?yàn)樗饕写鎯?chǔ)了實(shí)際的列值,所以某些查詢只使用索引就能夠完成全部查詢。(覆蓋索引)。總結(jié)下來(lái)索引有如下三個(gè)優(yōu)點(diǎn):- 索引大大減少了服務(wù)器需要掃描的數(shù)據(jù)量(B-Tree為查找樹(shù),時(shí)間復(fù)雜度O(logxN))
- 索引可以幫助服務(wù)器避免排序和臨時(shí)表(查找樹(shù)中序遍歷本身是有序的,當(dāng)可以使用到索引排序時(shí))
- 索引可以將隨機(jī)I/O變?yōu)轫樞騃/O(使用覆蓋索引時(shí)不用回表查詢)
三星系統(tǒng)
- 索引將相關(guān)的記錄放到一起則獲取一星
- 如果索引中的數(shù)據(jù)順序和查找中的排列順序一致則獲得二星
- 如果索引中的列包含了查詢中需要的全部列則獲得三星(覆蓋索引)
確保正確使用了索引
獨(dú)立的列(單列的時(shí)候)
獨(dú)立的列是指索引不能是表達(dá)式的一部分,也不能是函數(shù)的參數(shù)。下面兩種情況下不會(huì)使用索引:表示式的一部分:(其中user_id上有索引,主鍵索引)
SELECT * FROM user WHERE user_id +1 < 5;索引作為表達(dá)式的一部分(CURRENT_DATE為索引列)
WHERE TO_DAYS(CURRENT_DATE)=1234545;多列索引(多列的時(shí)候)
多列索引要選擇合適得索引列順序。因?yàn)樗饕前凑兆钭罅羞M(jìn)行排序。多列索引討論的就是如何排序索引列讓查詢更合理。 多列索引的順序問(wèn)題需要考慮的因素:- 索引列的經(jīng)驗(yàn)法則:將選擇性最高的列放到索引最前列。(選擇性高就是那一列能篩選出更少的數(shù)據(jù),那一列的選擇性就越高。例如:gender字段能大約篩選出 1/2 的數(shù)據(jù),主鍵能篩選出唯一一條數(shù)據(jù),那么主鍵的選擇性就更高,如果不考慮其它因素,涉及到這兩個(gè)列過(guò)濾時(shí),就應(yīng)該把主鍵列放在篩選條件的第一位)
- 高頻范圍字段一般要靠后放:例如:年齡字段。因?yàn)槭褂昧怂饕秶?右邊的索引列就無(wú)法再使用到索引。
- 對(duì)于可列舉字段使用到索引的方法:使用 IN關(guān)鍵字。例如 WHERE gender IN('m','f')。這樣后面也是可以用到索引的。同樣的還有 NOT IN
聚簇索引
聚簇索引 并不是一種單獨(dú)的索引類型,而是一種數(shù)據(jù)存儲(chǔ)方式。 聚簇索引和B-Tree索引有啥區(qū)別: B-Tree索引存放的是索引列,聚簇索引存放行的全部數(shù)據(jù)。數(shù)據(jù)分布如下: 值得注意的是:一個(gè)表只能有一個(gè)聚簇索引,InnoDB通過(guò)主鍵聚集數(shù)據(jù),如果沒(méi)有定義主鍵,選擇一個(gè)唯一非空索引代替。 優(yōu)缺點(diǎn)如下:| 優(yōu)點(diǎn) | 缺點(diǎn) |
| 可以把相關(guān)數(shù)據(jù)保存在一起。 數(shù)據(jù)訪問(wèn)更快。直接在索引中找,不用回表? ...... | 插入速度嚴(yán)重依賴插入順序 更新聚簇索引列代價(jià)高 可能導(dǎo)致全表掃描變慢 ...... |
覆蓋索引
定義:如果一個(gè)索引包含(或覆蓋)所有需要查詢的字段的值,就稱之為覆蓋索引。(包含:索引列比查找列多或相等 覆蓋:剛好一樣),MYSQL只能使用B-Tree索引做覆蓋索引。 覆蓋索引的好處:- 極大減少數(shù)據(jù)訪問(wèn)量,速度快+1
- 索引順序存儲(chǔ),所以I/O為順序I/O,速度快+2
- 如果嚴(yán)格符合所以定義,那肯定使用了覆蓋索引,哈哈
- 使用EXPALIN關(guān)鍵字 查看。如果在 Extra列 看到"Using index",證明使用了覆蓋索引。
| 字段值 | 含義 | 常見(jiàn)值及含義 | ||
| select_type | 查詢類型 | SIMPLE(簡(jiǎn)單SELECT,不使用UNION或子查詢等,普通WHERE可以) PRIMARY(最外層的SELECT) UNION(SELECT 之后使用了UNION) | ||
| type | 連接使用了哪種類別,有無(wú)使用索引,從最好到最差的連接類型為 const、eq_reg、ref、 range、index和ALL | const:表最多有一個(gè)匹配行,它將在查詢開(kāi)始時(shí)被讀取。因?yàn)閮H有一行, 在這行的列值可被優(yōu)化器剩余部分認(rèn)為是常數(shù)。const表很快,因?yàn)樗鼈冎蛔x取一次 ref:基于索引做掃描,可以用于單表掃描或者連接 range:只檢索給定范圍的行,使用一個(gè)索引來(lái)選擇行 index:僅僅掃描了索引 all:全表掃描,不適用索引,直接讀取表上的數(shù)據(jù) | ||
| key | 使用的索引 | 如果沒(méi)有選擇索引,鍵是NULL。要想強(qiáng)制MySQL使用或忽視possible_keys列中的索引, 在查詢中使用FORCE INDEX、USE INDEX或者IGNORE INDEX | ||
| key_len | 鍵長(zhǎng)度 | 在不損失精確度的情況下,長(zhǎng)度越短越好 | ||
| ref | 參考 | ref列顯示使用哪個(gè)列或常數(shù)與key一起從表中選擇行 | ||
| rows | 行數(shù) | MySQL認(rèn)為它執(zhí)行查詢時(shí)必須檢查的行數(shù)。 | ||
| Extra | 查詢?cè)敿?xì)信息 | Distinct:一旦MYSQL找到了與行相聯(lián)合匹配的行,就不再搜索了? Using filesort:使用文件排序 Using index:覆蓋索引 Using temporary:MySQL需要?jiǎng)?chuàng)建臨時(shí)表來(lái)存儲(chǔ)結(jié)果 Using where:使用了WHERE從句來(lái)限制哪些行將與下一張表匹配或者是返回給用戶 | ||
使用索引掃描來(lái)排序
注意:如果索引不能覆蓋查詢所需的全部的列,那就不得不每掃描一條索引記錄就回表查詢一次對(duì)應(yīng)的行。這基本上都是隨機(jī)I/O,因此按索引順序讀取數(shù)據(jù)的速度通常要比順序的全表掃描慢,尤其在I/O密集型工作時(shí)。查看是否使用了索引來(lái)排序:
如果 EXPLAIN 出來(lái)的 type 列的結(jié)果為 index,那說(shuō)明MySQL使用了索引掃描來(lái)排序。還是上面的那個(gè)例子: EXPLAIN SELECT id FROM tbl_role; 使用索引掃描排序好處: 查詢速度比沒(méi)有使用更快。因?yàn)樵谑褂盟饕樵儠r(shí),找到索引記錄之后需要回表查詢數(shù)據(jù),這種按索引順序讀取一般都是隨機(jī)I/O,比較慢。 使用到索引掃描來(lái)排序的條件: 只有當(dāng)索引的列順序和ORDER BY子句的順序完全一致,并且所有列的排序方向都一樣時(shí),MySQL才能夠使用索引來(lái)對(duì)結(jié)果做排序。如果查詢需要關(guān)聯(lián)多張表,則只有當(dāng)ORDER BY子句引用的字段全部為第一個(gè)表時(shí),才能使用索引做排序。 上述條件注意的地方:- 索引列和ORDER BY子句的順序完全一致:1、不包括主鍵索引2、滿足索引的最左匹配原則,比如索引列為KEY(age,name),那么ORDER BY age是可以的。
- 所有的方向都一樣:就是DESC 和ASC,不能再ORDER BY子句里面 出現(xiàn)有的正向排序,有的逆向排序,這也同時(shí)說(shuō)明了可以 DESC 或ASC,但是一般使用其中一種
- 關(guān)聯(lián)多張表,只要當(dāng)ORDER BY子句引用的字段全部為第一個(gè)表時(shí)才可以。這里的第一個(gè)表并不是指SQL語(yǔ)句中第一個(gè)表,而是優(yōu)化器優(yōu)化后的第一個(gè)表。
?發(fā)現(xiàn)type 不是 index,但是提示使用了索引
EXPLAIN SELECT * FROM user WHERE birth = '1993-01-02' ORDER BY grade,age;如果更改where 子句為 范圍比較,則不能使用到索引(而是文件排序)。(圖1)因?yàn)檫@里使用到了范圍查詢,后面的索引無(wú)法使用到,導(dǎo)致順序有問(wèn)題。同理,IN 關(guān)鍵字也是不可以使用的。(圖2)
EXPLAIN SELECT * FROM user WHERE birth > '1993-01-02' ORDER BY grade,age圖1
圖2
如果想使用索引,可以把birth放到ORDER BY后面
?還有一種情況是WHERE 子句不涉及索引字段,這時(shí)候無(wú)法使用索引掃描排序。
?冗余和重復(fù)索引
重復(fù)索引:是指在相同列上按照相同順序創(chuàng)建的相同類型的索引。應(yīng)該盡量避免冗余和重復(fù)索引,如果發(fā)現(xiàn),一般是要?jiǎng)h掉。- 相同列,相同順序,相同類型
- 盡量避免,發(fā)現(xiàn)刪除
優(yōu)化排序
如何處理排序和分頁(yè)時(shí) 用戶查看翻頁(yè)到很靠后的數(shù)據(jù)? SELECT * FROM profiles WHERE sex = 'M' ORDER BY rating limit 10000,10總結(jié)
在選擇索引和編寫(xiě)利用這些索引的查詢時(shí),有如下三個(gè)原則始終需要記住:轉(zhuǎn)載于:https://www.cnblogs.com/uodut/p/7070633.html
總結(jié)
- 上一篇: java hascode
- 下一篇: 51nod 1421 最大MOD值