學過伺服器端開發的朋友一定知道,程式沒有資料庫索引也可以執行。但是所有學習資料庫的資料、教程,一定會有大量的篇幅在介紹資料庫索引,各種後端開發工作的面試也一定繞不開索引,甚至可以說資料庫索引是從後端初級開發跨越到高階開發的屠龍寶刀,那麼索引到底在服務端程式中起著怎樣的作用呢?
這篇文章是一系列資料庫索引文章中的第一篇,這個系列包括了下面四篇文章:
-
資料庫索引是什麼?新華字典來幫你 —— 理解
-
資料庫索引融會貫通 —— 深入
-
20分鐘資料庫索引設計實戰 —— 實戰
-
資料庫索引為什麼用B+樹實現? —— 擴充套件
這一系列涵蓋了資料庫索引從理論到實踐的一系列知識,一站式解決了從理解到融會貫通的全過程,相信每一篇文章都可以給你帶來更深入的體驗。
什麼是資料庫索引?
用一句話來描述:資料庫索引就是一種加快海量資料查詢的關鍵技術。現在還不理解這句話?不要緊,往下看,20分鐘以後你就能自己做出這樣的總結來了。
首先給大家看一張圖片
這本書大家一定都很熟悉,小學入門第一課一定就是教小朋友們學習如何使用這本書。那這和我們的資料庫索引有啥關係呢?彆著急,我們翻開第一頁看看。
請大家注意右上角的那一排文字,原來目錄就是傳說中的索引呀!從前面的“一句話描述”我們可以知道,索引的目的就是為了加快資料查詢。那麼我們查字典時翻的第一個地方是哪裡呢,我相信大部分人都會先翻到拼音目錄,畢竟現在很多人都是提筆忘字了?。
資料庫索引的作用和拼音目錄是一樣的,就是最快速的鎖定目標資料所在的位置範圍。比如我們在這裡要查險
這個字,那麼我們找到了Xx
部分之後就能按順序找到xian
這個拼音所在的頁碼,根據前後的頁碼我們可以知道這個字一定是在519頁到523頁之間的,範圍一下子就縮小到只有4頁了。這相比我們從頭翻到尾可是快多了,這時候就出現了第一個專業術語——全表掃描,也就是我們說的從頭找到尾了。
果然,我們在第521頁找到了我們要找的“險”字。
那麼現在我們就知道資料庫索引大概是一個什麼東西了:資料庫索引是一個類似於目錄這樣的用來加快資料查詢的技術。
什麼是聯合索引?
相信大家都見過一些包含多個欄位的資料庫索引,比如INDEX idx_test(col_a, col_b)
。這種包含多個欄位的索引就被稱為**“聯合索引”**。那麼在多個欄位上建索引能起到什麼樣的作用呢?下面還是以新華字典為例,來看看到底什麼是聯合索引。
新華字典裡還有一種目錄被稱為“部首目錄”,下面可以看到,要使用這個目錄我們首先會根據部首的筆畫數找到對應該能的部分,然後可以在裡面找到我們想找的部首。比如如果我們還是要找險
字所在的位置:
找到部首後,右邊的頁碼還不是險
字真正的頁碼,我們還需要根據右邊的頁碼找到對應部首在檢字表中的位置。找到第93頁的檢字表後我們就可以根據險
字餘下的筆畫數(7畫)在“6-8畫”這一部分裡找到險
字真正的頁碼了。
在這個過程中,我們按順序使用了“兩個目錄”,一個叫做“部首目錄”,一個叫做“檢字表”。並且我們可以看到上圖中檢字表的內容都是按部首分門別類組織的。這兩個部分合在一起就是我們在本節討論的主題——聯合索引。即通過第一個欄位的值(部首)在第一級索引中找到對應的第二級索引位置(檢字表頁碼),然後在第二級索引中根據第二個欄位的值(筆畫)找到符合條件的資料所在的位置(險
字的真正頁碼)。
最左字首匹配
從前面使用部首目錄的例子中可以看出,如果我們不知道一個字的部首是什麼的話,那基本是沒辦法使用這個目錄的。這說明僅僅通過筆畫數(第二個欄位)是沒辦法使用部首目錄的。
這就引申出了聯合索引的一個規則:聯合索引中的欄位,只有某個欄位(筆畫)左邊的所有欄位(部首)都被使用了,才能使用該欄位上的索引。例如,有索引INDEX idx_i1(col_a, col_b)
,如果查詢條件為where col_b = 1
,則無法使用索引idx_i1
。
但是如果我們知道部首但是不知道筆畫數,比如不知道“橫折豎彎勾”是算一筆還是兩筆,那我們仍然可以使用“部首目錄”部分的內容,只是要把“檢字表”對應部首裡的所有字都看一遍就能找到我們要找的字了。
這就引申出了聯合索引的另一個規則:聯合索引中的欄位,即使某個欄位(部首)右邊的其他欄位(筆畫)沒有被使用,該欄位之前(含)的所有欄位仍然可以正常使用索引。例如,有索引INDEX idx_i2(col_a, col_b, col_c)
,則查詢條件where col_a = 1 and col_b = 2
在欄位col_a
和col_b
上仍然可以走索引。
但是,如果我們在確定部首後,不知道一個字到底是兩畫還是三畫,這種情況下我們只需要在對應部首的兩畫和三畫部分中找就可以了,也就是說我們仍然使用了檢字表中的內容。所以,使用範圍條件查詢時也是可以使用索引的。
最後,我們可以完整地表述一下最左字首匹配原則的含義:對於一個聯合索引,如果有一個SQL查詢語句需要執行,則只有從索引最左邊的第一個欄位開始到SQL語句查詢條件中不包含的欄位(不含)或範圍條件欄位(含)為止的部分才會使用索引進行加速。
這裡出現了一個之前沒有提到的點,就是範圍條件欄位也會結束對索引上後續欄位的使用,這是為什麼呢?具體原因的解釋涉及到了更深層次的知識,在接下來的第二篇文章的最後就可以找到答案。
什麼是聚集索引?
從上文的部首目錄和拼音目錄同時存在但是實際的字典內容只有一份這一點上可以看出,在資料庫中一張表上是可以有多個索引的。那麼不同的索引之間有什麼區別呢?
我們在新華字典的側面可以看到一個V字形的一個個黑色小方塊,有很多人都會在側面寫上A, B, C, D
這樣對應的拼音字母。因為字典中所有的字都是按照拼音順序排列的,有時候直接使用首字母翻開對應的部分查也很快。
像拼音目錄這樣的索引,資料會根據索引中的順序進行排列和組織的,這樣的索引就被稱為聚集索引,而非聚集索引就是其他的一般索引。因為資料只能按照一種規則排序,所以一張表至多有一個聚集索引,但可以有多個非聚集索引。
在MySQL資料庫的InnoDB
儲存引擎中,主鍵索引就是聚集索引,所有資料都會按照主鍵索引進行組織;而在MyISAM
儲存引擎中,就沒有聚集索引了,因為MyISAM儲存引擎中的資料不是按索引順序進行儲存的。