MySQL中一些關於索引的知識點

2021-09-25 22:52:23 字數 3616 閱讀 6320

索引是一種資料結構,其作用就是用來提高資料查詢效率。比較常用的比喻就是將其模擬為書籍的目錄。通過目錄可以精確的找到某一章節的內容所在頁。

在資料量較小的時候使用索引其實也沒有什麼意義,即使沒有索引需要一條一條遍歷資料對於計算機來說也並不需要太多時間。而一旦資料量較大,要保證我們能正常的對外提供服務,保證使用者使用體驗那麼索引就是必要的了。

索引時一種資料結構,為了應對不同的場景會有多種實現。在mysql中主要就是hash索引和b+tree。

hash索引

hash相信大家應該都很熟悉,hash是一種key-value形式的資料結構。實現一般是陣列+鍊錶的結構,通過hash函式計算出key在陣列中的位置,然後如果出現hash衝突就通過鍊錶來解決(拉鍊法)。當然還有其他的解決hash衝突的方法。hash這種資料結構是很常用的,比如我們系統使用hashmap來構建熱點資料快取,訪問效率很好。

hash結構存資料首先通過計算key的hash值來確定其在陣列中的位置,如果有衝突就在該陣列位置建乙個鍊錶。這樣很明顯有幾個問題:

所以我們可以知道的是hash索引適用於快速選取某一行的資料。

從名字上看這明顯是一種樹結構,在大學期間資料結構的課本上樹結構是必講的。樹結構是一種特別重要的資料結構,在很多地方都會使用到。

上面我們說到hash索引無法進行範圍查詢,在樹結構中也有一種方便進行有序查詢的結構–二叉搜尋樹。二叉搜尋樹的結構中要求父節點的值大於左孩子節點並且小於右孩子節點,如下圖。

上圖中二叉樹的查詢的時間複雜度為o(log(n)),當然要保證o(log(n))的時間複雜度就需要保證二叉樹時刻保持平衡。

b-tree

要了解b+tree首先就得了解b-tree,b-tree是一種平衡樹,這裡的b指的是balance而不是binary,更確切的說b-tree是一種多路平衡搜尋樹。

多路平衡搜尋樹如下圖:

這是一種2-3樹,意思就是每個節點存有兩個值,同時每個節點分支數為3,從上圖中可以看出來著中結構很適合查詢資料。每個節點的左子樹的值都是小於當前節點中最小的值,中間的子樹的值全都是在當前節點兩個值的中間,而右子樹的值全都大於當前節點的最大值。

比如我們要查詢24這個值:

首先從根節點判斷24在根節點(15,25)之間,所以左右子樹排除,從中間查詢。

然後找到中間子樹的根節點(18,22),比較發現24大於該節點最大值,排除左子樹和中間子樹。

找到右子樹,判斷節點大值剛好等於24,查詢結束

基於上面的流程可以總結b樹的搜尋:

可以看出其搜尋效能相當於在關鍵字集合內做一次二分查詢。從這裡看來好像b-tree沒有什麼問題,但是需要注意到的是在b-tree中每乙個節點都是儲存索引關鍵字以及其代表的具體行資料。而在mysql中資料庫載入資料是以頁為單位載入,每一頁的大小是固定的(預設16k)。如果每乙個節點都儲存所有的值,那麼一頁中能存下的節點就會很少,一次查詢可能就會進行多次從記憶體中去載入資料,導致效能降低。

b+tree

b+tree是對b-tree的乙個變種,讓其更加適應於進行外部儲存檔案索引。

兩者之前最大的不同就在於b-tree的每個節點都儲存所有的資料,而b+tree需要儲存的資料都在葉子節點上,並且增加了順序訪問指標,每個葉子節點都有指向下乙個相鄰的葉子節點的位址。這樣的結構保證了在乙個記憶體頁中可以存下更多的索引節點,並且更加適合進行範圍查詢。

索引因為儲存引擎負責實現索引,所以接下來討論索引都是基於mysql的innodb引擎。

聚簇索引

聚簇的意思是表示資料行和相鄰的鍵值聚簇的儲存在一起。一些資料庫允許選擇具體的某乙個索引作為聚簇索引,而在innodb的實現中直接將主鍵索引指定為聚簇索引。如果沒有定義主鍵,innodb 會選擇乙個唯一的非空索引來代替主鍵索引。如果同樣沒有定義這樣的索引,innodb會隱式定義乙個主鍵來作為聚簇索引(row_id)。

聚簇索引實例如圖:

非聚簇索引索引

在innodb中除主鍵索引外其他都是非聚簇索引,所以也叫非主鍵索引。非主鍵索引的葉節點並不是儲存一行的值,而是儲存具體行的主鍵值。不滿足聚簇的定義。

非聚簇索引實例如圖:

聚簇索引和非聚簇索引在查詢時的差異

由上面的兩種索引例項圖就可以看出來,在查詢時如果是通過主鍵索引查詢的話直接查詢到資料行然後返回。但是如果是通過非主鍵索引查詢的話首先需要通過該索引確定主鍵,然後通過得到的主鍵從主鍵索引中查到具體行的資料,後面的通過得到的主鍵從主鍵索引中獲取資料的過程被稱為回表。

回表的過程使得通過普通索引查詢較主鍵索引查詢多了一步,在很多情況下效率相對較低。所以在我們的查詢過程中如果能夠僅通過主鍵確定資料那最好就是直接使用主鍵進行查詢。

覆蓋索引

上面介紹了通過非主鍵查詢會有乙個回表的過程,但是需要注意的是並不是每乙個查詢都存在回表這一步,對於乙個普通索引來說其葉節點儲存的是主鍵的值,那麼假設我現在需要的資料也僅僅就是主鍵的值呢?通過普通索引取到主鍵的值後就並不需要再到主鍵索引中查,那麼也就不存在回表這一過程了。

上面例子中該非主鍵索引已經存在了我們所需要的值,所以該索引也被稱為覆蓋索引。覆蓋索引並不是乙個固定的結構,可以使單索引(乙個欄位的索引),也可以使復合索引,凡是能夠直接提供查詢結果而不需要進行回表過程的都可以被稱為覆蓋索引。

很多時候我們不可能僅僅通過主鍵來確定資料,使用普通索引可能會導致低效,所以覆蓋索引在日常開發過程中也是乙個很常用的效能優化的手段。

當然覆蓋索引頁並不都是好的,比如我現在建立了乙個索引index(a,b)。由a,b兩個欄位來建立索引,好處已經說過了就是查詢ab欄位時不會回表,但是如果僅僅通過b欄位來查詢就無法走這個索引了。建立的索引的索引項是按照索引定義裡面出現的字段順序排序的。

最左字首原則

假設現在存在索引index(a,b),那麼如果通過a和b來查詢能夠應用該索引,單獨使用a來查詢也能應用到該索引,但是如果單獨使用b來查詢則無法應用到該索引。這就是最左字首原則,在匹配索引時回匹配索引最左邊的n個字段,能匹配上就可以應用該索引。

由於最左字首原則的存在也就要求我們在建立索引時可能需要考慮更多的事情。

首先需要清楚的事索引是一種資料結構,建立索引時需要消耗儲存空間的,所以索引並不是建立的越多越好,而是應該根據需求盡可能的減少索引的數量。

而最左字首原則的存在就使得乙個聯合索引可以被當成多個索引來使用,當然前提是設計好索引中字段的順序(實際上最左字首原則也並不是僅僅適用於聯合索引,對於字串索引也使用,字串索引中最左n個字元相當於聯合索引中的最左n個字段)。

比如index(a,b),有了這個索引後我們就不需要單獨為a建立索引,所以在設計聯合索引時一般將使用頻率較高的字段放在前面。

然後是將區分度較高的字段靠前,區分度就是欄位中值的重複率,重複率越低區分度越高。比如性別就不適合作為索引,區分度越高的字段經過一次篩選能過濾掉更多的行。

然後還需要考慮的是字段的大小,由於索引也需要佔據空間所以一般選用較小的字段。

mysql運維內參:mysql、galera、inception核心原理與最佳實踐

php中一些知識

file 的路徑是當前 所在檔案 dirname dirname file 得到的是檔案上一層目錄名 dirname file 得到的是檔案所在層目錄名 require其實是乙個直譯器解釋的過程,比如當我們在乙個檔案中require另乙個檔案的時候,其實是先解釋另乙個檔案。php中的檔案a的過程中假...

jquery中一些知識

var form el input type hidden input type text textarea,select asss find form el each function 在id為asss表單中可以查詢input type型別為hidden,text的按鈕,也查詢textarea,s...

關於mysql的一些知識

sql 萬用字元 可以匹配任意字元 包括空字串 萬用字元 表示乙個字元不包含空 資料庫命名 字母數字下劃線 可以以數字開頭 但是不要用系統保留 關鍵字 盡量使用小寫 linux嚴格區分大小寫 名字比較長的時候 使用 下劃線做連線 檢視資料庫建立 show create database db nam...