自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL遵循最左前綴匹配原則!面試官:回去等通知吧

數(shù)據(jù)庫 MySQL
MySQL 8.0.13 版本中,對于range查詢(什么是range后面會提到),引入了索引跳躍掃描(Index Skip Scan)優(yōu)化,支持不符合組合索引最左前綴原則條件下的SQL,依然能夠使用組合索引,減少不必要的掃描。

我們都知道,MySQL的Innodb引擎中,索引是通過B+樹來實現(xiàn)的。不管是普通索引還是聯(lián)合索引,都需要構(gòu)造一個B+樹的索引結(jié)構(gòu)。

那么,我們都知道普通索引的存儲結(jié)構(gòu)中在B+樹的每個非節(jié)點上記錄的索引的值,而這棵B+樹的葉子節(jié)點上記錄的是聚簇索引(主鍵索引)的值。

如:

圖片

那么,如果是聯(lián)合索引的話,這棵B+樹又是如何存儲的呢?

在聯(lián)合索引中,聯(lián)合索引(name,age)也是一個B+樹,非葉子節(jié)點中記錄的是name,age兩個字段的值,葉子節(jié)點中記錄的是name,age兩個字段以及主鍵id的值。

圖片

?在存儲的過程中,如上圖所示,當(dāng)age不同時,按照age排序,當(dāng)age相同時,則按照name排序。

所以,了解了索引的存儲結(jié)構(gòu)之后,我們就很容易理解最左前綴匹配了:因為索引底層是一個B+樹,如果是聯(lián)合索引的話,在構(gòu)造B+樹的時候,會先按照左邊的key進(jìn)行排序,左邊的key相同時再依次按照右邊的key排序。

所以,在通過索引查詢的時候,也需要遵守最左前綴匹配的原則,也就是需要從聯(lián)合索引的最左邊開始進(jìn)行匹配,這時候就要求查詢語句的where條件中,包含最左邊的索引的值。

在了解了最左前綴匹配之后,日常我們在工作中,經(jīng)常在簡歷索引以及查詢的時候,都會基于這個默認(rèn)的約定進(jìn)行索引的設(shè)計和SQL的優(yōu)化。

大家都默認(rèn)MySQL一定是遵循最左前綴匹配的。會認(rèn)為當(dāng)一個age,name的聯(lián)合索引存在時,如果查詢語句中不包含age作為條件,就一定不走索引。

MySQL一定是遵循最左前綴匹配的,這句話在以前是正確的,沒有任何毛病。但是在MySQL 8.0中,就不一定了。?

索引跳躍掃描

MySQL 8.0.13 版本中,對于range查詢(什么是range后面會提到),引入了索引跳躍掃描(Index Skip Scan)優(yōu)化,支持不符合組合索引最左前綴原則條件下的SQL,依然能夠使用組合索引,減少不必要的掃描。

通過一個例子給大家解釋一下,首先有下面這樣一張表(參考了MySQL官網(wǎng)的例子,但是我做了些改動和優(yōu)化):

圖片

通過上面的SQL,先創(chuàng)建一張t1表,并把f1,f2兩個字段設(shè)置為聯(lián)合索引。之后再向其中插入一些記錄。

分別在MySQL 5.7.9和MySQL 8.0.30上執(zhí)行:

圖片

執(zhí)行結(jié)果如下:

圖片

可以看到,主要有以下幾個區(qū)別:

MySQL 5.7中,type = index,rows=160,extra=Using where;Using index

MySQL 8.0中,type = range,rows=16,extra=Using where;Using index for skip scan

這里面的type指的是掃描方式,range表示的是范圍掃描,index表示的是索引樹掃描,通常情況下,range要比index快得多。

從rows上也能看得出來,使用index的掃描方式共掃描了160行,而使用range的掃描方式只掃描了16行。

?接著,重點來了,那就是為啥MySQL 8.0中的掃描方式可以更快呢?主要是因為Using index for skip scan 表示他用到了索引跳躍掃描的技術(shù)。

也就是說,雖然我們的SQL中,沒有遵循最左前綴原則,只使用了f2作為查詢條件,但是經(jīng)過MySQL 8.0的優(yōu)化以后,還是通過索引跳躍掃描的方式用到了索引了。?

優(yōu)化原理

在MySQL 8.0.13 及以后的版本中,SELECT f1, f2 FROM t1 WHERE f2 = 40;SQL執(zhí)行過程如下:

  • 獲取f1字段第一個唯一值,也就是f1=1。
  • 構(gòu)造f1=1 and f2 = 40,進(jìn)行范圍查詢。
  • 獲取f1字段第二個唯一值,也就是f1=2。
  • 構(gòu)造f1=2 and f2 = 40,進(jìn)行范圍查詢。
  • 一直掃描完f1字段所有的唯一值,最后將結(jié)果合并返回。

也就是說,最終執(zhí)行的SQL語句是像下面這樣的:?

圖片

即,MySQL的優(yōu)化器幫我們把聯(lián)合索引中的f1字段作為查詢條件進(jìn)行查詢了。

限制條件

?在知道了索引跳躍掃描的執(zhí)行過程之后,很多聰明的讀者其實就會發(fā)現(xiàn),這種查詢優(yōu)化比較適合于f1的取值范圍比較少,區(qū)分度不高的情況,一旦f1的區(qū)分度特別高的話,這種查詢可能會更慢。

所以,真正要不要走索引跳躍掃描,還是要經(jīng)過MySQL的優(yōu)化器進(jìn)行成本預(yù)估之后做決定的。

所以,這種優(yōu)化一般用于那種聯(lián)合索引中第一個字段區(qū)分度不高的情況。但是話又說回來了,我們一般不太會把區(qū)分度不高的字段放在聯(lián)合索引的左邊,不過事無絕對,既然MySQL給了一個優(yōu)化的方案,就說明還是有這樣的訴求的。

但是,我們不能依賴他這個優(yōu)化,建立索引的時候,還是優(yōu)先把區(qū)分度高的,查詢頻繁的字段放到聯(lián)合索引的左邊。?

除此之外,在MySQL官網(wǎng)中,還提到索引跳躍掃描還有一些其他的限制條件:

  • 表T至少有一個聯(lián)合索引,但是對于聯(lián)合索引(A,B,C,D)來說,A和D可以是空的,但B和C必須是非空的。
  • 查詢必須只能依賴一張表,不能多表JOIN。
  • 查詢中不能使用GROUP BY或DISTINCT語句?。
  • 查詢的字段必須是索引中的列。
責(zé)任編輯:姜華 來源: Hollis
相關(guān)推薦

2025-02-13 00:00:00

TCP網(wǎng)絡(luò)通信

2020-12-16 08:05:54

Mybatis面試動態(tài)代理

2024-05-27 09:23:23

2020-12-02 06:12:27

TCPIP面試

2021-02-06 09:21:17

MySQL索引面試

2022-11-16 17:10:25

MySQL數(shù)據(jù)事務(wù)

2024-02-26 12:38:21

MySQLInnoDB跨度

2021-12-09 07:22:52

索引下推前綴

2024-08-05 01:26:54

2022-09-29 07:30:57

數(shù)據(jù)庫索引字段

2023-09-01 15:27:31

2022-03-21 09:05:18

volatileCPUJava

2023-07-13 08:19:30

HaspMapRedis元素

2020-12-14 08:07:06

Mybatis源碼java

2024-01-15 06:42:00

高并發(fā)熱點賬戶數(shù)據(jù)庫

2025-03-26 01:25:00

MySQL優(yōu)化事務(wù)

2024-06-12 09:23:37

2024-08-21 10:28:54

Redis數(shù)據(jù)結(jié)構(gòu)內(nèi)存

2022-05-23 08:43:02

BigIntJavaScript內(nèi)置對象

2022-11-15 17:45:46

數(shù)據(jù)庫MySQL
點贊
收藏

51CTO技術(shù)棧公眾號