說(shuō)在前面
數(shù)據(jù)庫(kù)超級(jí)重要,這個(gè)大家應(yīng)該清楚,學(xué)過(guò)數(shù)據(jù)庫(kù)的朋友一定知道,數(shù)據(jù)庫(kù)在使用時(shí),即使沒(méi)有加索引也可以運(yùn)行,但是所有學(xué)習(xí)數(shù)據(jù)庫(kù)的資料、教程,一定會(huì)有大量的篇幅在介紹數(shù)據(jù)庫(kù)索引,各種后端開發(fā)工作的面試也一定繞不開索引,甚至可以說(shuō)數(shù)據(jù)庫(kù)索引是從后端初級(jí)開發(fā)跨越到高級(jí)開發(fā)的屠龍寶刀,那么索引到底在服務(wù)端程序中起著怎樣的作用呢?
到底什么是索引?
用一句話來(lái)描述:數(shù)據(jù)庫(kù)索引就是一種加快海量數(shù)據(jù)查詢的關(guān)鍵技術(shù)?,F(xiàn)在還不理解這句話?不要緊,往下看,20分鐘以后你就能自己做出這樣的總結(jié)來(lái)了。
首先給大家看一張圖片
這本書大家一定都很熟悉,小學(xué)入門第一課一定就是教小朋友們學(xué)習(xí)如何使用這本書。那這和我們的數(shù)據(jù)庫(kù)索引有啥關(guān)系呢?別著急,我們翻開第一頁(yè)看看。
注意右上角的那一排文字,其實(shí)目錄就是傳說(shuō)中的索引!從前面的“一句話描述”我們可以知道,索引的目的就是為了加快數(shù)據(jù)查詢。那么我們查字典時(shí)翻的第一個(gè)地方是哪里呢,我相信大部分人都會(huì)先翻到拼音目錄,畢竟現(xiàn)在很多人都是提筆忘字了?。
數(shù)據(jù)庫(kù)索引的作用和拼音目錄是一樣的,就是最快速的鎖定目標(biāo)數(shù)據(jù)所在的位置范圍。比如我們?cè)谶@里要查 險(xiǎn) 這個(gè)字,那么我們找到了Xx部分之后就能按順序找到xian這個(gè)拼音所在的頁(yè)碼,根據(jù)前后的頁(yè)碼我們可以知道這個(gè)字一定是在519頁(yè)到523頁(yè)之間的,范圍一下子就縮小到只有4頁(yè)了。這相比我們從頭翻到尾可是快多了,這時(shí)候就出現(xiàn)了第一個(gè)專業(yè)術(shù)語(yǔ)——全表掃描,也就是我們說(shuō)的從頭找到尾了。
果然,我們?cè)诘?21頁(yè)找到了我們要找的“險(xiǎn)”字。
那么現(xiàn)在我們就知道數(shù)據(jù)庫(kù)索引大概是一個(gè)什么東西了:數(shù)據(jù)庫(kù)索引是一個(gè)類似于目錄這樣的用來(lái)加快數(shù)據(jù)查詢的技術(shù)。
什么是聯(lián)合索引?
相信大家都見過(guò)一些包含多個(gè)字段的數(shù)據(jù)庫(kù)索引,比如 INDEX idx_test(col_a,col_b)。這種包含多個(gè)字段的索引就被稱為“聯(lián)合索引”。那么在多個(gè)字段上建索引能起到什么樣的作用呢?下面還是以新華字典為例,來(lái)看看到底什么是聯(lián)合索引。
新華字典里還有一種目錄被稱為“部首目錄”,下面可以看到,要使用這個(gè)目錄我們首先會(huì)根據(jù)部首的筆畫數(shù)找到對(duì)應(yīng)該能的部分,然后可以在里面找到我們想找的部首。比如如果我們還是要找 險(xiǎn)字所在的位置:
找到部首后,右邊的頁(yè)碼還不是 險(xiǎn)字真正的頁(yè)碼,我們還需要根據(jù)右邊的頁(yè)碼找到對(duì)應(yīng)部首在檢字表中的位置。找到第93頁(yè)的檢字表后我們就可以根據(jù) 險(xiǎn)字余下的筆畫數(shù)(7畫)在“6-8畫”這一部分里找到 險(xiǎn)字真正的頁(yè)碼了。
在這個(gè)過(guò)程中,我們按順序使用了“兩個(gè)目錄”,一個(gè)叫做“部首目錄”,一個(gè)叫做“檢字表”。并且我們可以看到上圖中檢字表的內(nèi)容都是按部首分門別類組織的。這兩個(gè)部分合在一起就是我們?cè)诒竟?jié)討論的主題——聯(lián)合索引。即通過(guò)第一個(gè)字段的值(部首)在第一級(jí)索引中找到對(duì)應(yīng)的第二級(jí)索引位置(檢字表頁(yè)碼),然后在第二級(jí)索引中根據(jù)第二個(gè)字段的值(筆畫)找到符合條件的數(shù)據(jù)所在的位置(險(xiǎn)字的真正頁(yè)碼)。
最左前綴匹配
從前面使用部首目錄的例子中可以看出,如果我們不知道一個(gè)字的部首是什么的話,那基本是沒(méi)辦法使用這個(gè)目錄的。這說(shuō)明僅僅通過(guò)筆畫數(shù)(第二個(gè)字段)是沒(méi)辦法使用部首目錄的。
這就引申出了聯(lián)合索引的一個(gè)規(guī)則:聯(lián)合索引中的字段,只有某個(gè)字段(筆畫)左邊的所有字段(部首)都被使用了,才能使用該字段上的索引。例如,有索引 INDEX idx_i1(col_a,col_b),如果查詢條件為 wherecol_b =1,則無(wú)法使用索引 idx_i1。
但是如果我們知道部首但是不知道筆畫數(shù),比如不知道“橫折豎彎勾”是算一筆還是兩筆,那我們?nèi)匀豢梢允褂谩安渴啄夸洝辈糠值膬?nèi)容,只是要把“檢字表”對(duì)應(yīng)部首里的所有字都看一遍就能找到我們要找的字了。
這就引申出了聯(lián)合索引的另一個(gè)規(guī)則:聯(lián)合索引中的字段,即使某個(gè)字段(部首)右邊的其他字段(筆畫)沒(méi)有被使用,該字段之前(含)的所有字段仍然可以正常使用索引。例如,有索引 INDEX idx_i2(col_a,col_b,col_c),則查詢條件 wherecol_a =1andcol_b =2在字段 col_a和 col_b上仍然可以走索引。
但是,如果我們?cè)诖_定部首后,不知道一個(gè)字到底是兩畫還是三畫,這種情況下我們只需要在對(duì)應(yīng)部首的兩畫和三畫部分中找就可以了,也就是說(shuō)我們?nèi)匀皇褂昧藱z字表中的內(nèi)容。所以,使用范圍條件查詢時(shí)也是可以使用索引的。
最后,我們可以完整地表述一下最左前綴匹配原則的含義:對(duì)于一個(gè)聯(lián)合索引,如果有一個(gè)SQL查詢語(yǔ)句需要執(zhí)行,則只有從索引最左邊的第一個(gè)字段開始到SQL語(yǔ)句查詢條件中不包含的字段(不含)或范圍條件字段(含)為止的部分才會(huì)使用索引進(jìn)行加速。
什么是聚集索引?
從上文的部首目錄和拼音目錄同時(shí)存在但是實(shí)際的字典內(nèi)容只有一份這一點(diǎn)上可以看出,在數(shù)據(jù)庫(kù)中一張表上是可以有多個(gè)索引的。那么不同的索引之間有什么區(qū)別呢?
我們?cè)谛氯A字典的側(cè)面可以看到一個(gè)V字形的一個(gè)個(gè)黑色小方塊,有很多人都會(huì)在側(cè)面寫上 A, B, C, D這樣對(duì)應(yīng)的拼音字母。因?yàn)樽值渲兴械淖侄际前凑掌匆繇樞蚺帕械?,有時(shí)候直接使用首字母翻開對(duì)應(yīng)的部分查也很快。
像拼音目錄這樣的索引,數(shù)據(jù)會(huì)根據(jù)索引中的順序進(jìn)行排列和組織的,這樣的索引就被稱為聚集索引,而非聚集索引就是其他的一般索引。因?yàn)閿?shù)據(jù)只能按照一種規(guī)則排序,所以一張表至多有一個(gè)聚集索引,但可以有多個(gè)非聚集索引。
在 MySQL數(shù)據(jù)庫(kù)的 InnoDB存儲(chǔ)引擎中,主鍵索引就是聚集索引,所有數(shù)據(jù)都會(huì)按照主鍵索引進(jìn)行組織;而在MyISAM存儲(chǔ)引擎中,就沒(méi)有聚集索引了,因?yàn)镸yISAM存儲(chǔ)引擎中的數(shù)據(jù)不是按索引順序進(jìn)行存儲(chǔ)的。
好了,到此為止,關(guān)于非常重要的數(shù)據(jù)庫(kù)索引的概念應(yīng)該非常清楚了,對(duì)吧。后面繼續(xù)再出實(shí)戰(zhàn)和優(yōu)化方面的文章!
原文鏈接
作者:兜里有辣條