為什麼要使用索引?

2022-08-27 17:48:13 字數 3557 閱讀 8461

什麼是索引?

mysql 官方對索引的定義為:索引(index)是幫助 mysql 高效獲取資料的資料結構。

快速到底

影響資料庫效率的原因千千萬萬,使用索引是為了解決哪方面的資料庫的瓶頸?

點一

mysql 資料庫儲存資料最終是以檔案的形式儲存到硬碟的。一般來說,我們在程式中使用的時候肯定要把磁碟檔案中的資料讀到記憶體中。那麼就這個 「讀」 的過程是什麼樣子的呢?磁碟讀取資料靠的是機械運動,每次讀取資料花費的時間可以分為尋道時間、旋轉延遲、傳輸時間三個部分,尋道時間指的是磁臂移動到指定磁軌所需要的時間

,主流磁碟的尋道時間一般在5ms以下;

旋轉延遲就是我們經常聽說的

磁碟轉速,比如乙個磁碟7200轉,表示每分鐘能轉7200次,也就是說1秒鐘能轉120次,旋轉延遲就是1/120/2 = 4.17ms(旋轉延遲等於磁碟轉動半圈時間);傳輸時間指的是從磁碟

讀出或將資料

寫入磁碟的時間,一般在零點幾毫秒,相對於前兩個時間

可以忽略不計。那麼訪問一次磁碟的時間,即

一次磁碟io的時間約等於

5+4.17 = 9ms左右,聽起來還挺不錯的,但要知道一台 500 - mips

的機器每秒可以執行5億條指令,因為指令依靠的是電的性質,換句話說執行一次io的時間可以執行40萬條指令

圖 1 -1:計算機硬體延遲的對比圖

所以,問題的癥結就在於磁碟 io 是非常高昂的操作。

解決方案:

①:計算機作業系統做了一些優化,當一次io時,不光把當前磁碟位址的資料,而是把

相鄰的資料也都讀取到記憶體緩衝區內,因為區域性預讀性原理告訴我們,當計算機訪問乙個位址的資料的時候,與其相鄰的資料也會很快被訪問到。每一次io讀取的資料我們稱之為一頁(page)。具體一頁有多大資料跟作業系統有關,一般為4k或8k,也就是我們讀取一頁內的資料時候,實際上才發生了一次io(一次 io 的資料報括當前要讀取的磁碟位址的資料+與之相鄰的資料),這個理論對於索引的資料結構設計非常有幫助。

②:每次查詢資料時把磁碟io次數控制在乙個很小的數量級

很明顯:第①種解決方案是系統已經提供好的。要想實現第二種解決方案就需要一種穩定的資料結構能夠滿足幾乎每次查詢資料進行磁碟的 io 次數是很少的。這個條件可以解釋為:每次查詢資料進行的 io 次數都很少,說明這個資料結構不能像紅黑樹一樣樹的高度不可控,於是乙個高度可控的多路搜尋樹就產生了,這就是 b + 樹。

在這裡要闡述清楚一件事情:那麼b + 樹的每乙個節點(以磁碟的角度可以稱作:磁碟塊;參照下圖)究竟存的是什麼?以

一張表的 id 列為例,也就是主鍵列是如果是索引的話,那麼這張表的每乙個 id 都會以 b+ 樹的每乙個節點儲存到 b+ 樹上,如果資料過多,乙個節點就會儲存多個 id(這裡只是形象的認識,下面有詳細解釋)。

b + 樹

圖 1-2:b+ 樹資料結構圖

如上圖,是一顆b +樹,關於b +樹的定義可以參見 b + 樹,這裡只說一些重點,淺藍色的塊我們稱之為乙個磁碟塊,可以看到每個磁碟塊包含幾個資料項(深藍色所示)和指標(黃色所示),如磁碟塊1包含

資料項17和35(如果以 id 為例的話,就代表乙個節點(磁碟塊)存放了兩個 id),包含

指標p1、p2、p3,p1表示小於17的磁碟塊,p2表示在17和35之間的磁碟塊,p3表示大於35的磁碟塊。

真實的資料存在於葉子節點即3、5、9、10、13、15、28、29、36、60、75、79、90、99。非葉子節點

不儲存真實的資料,只儲存指引搜尋方向的資料項(也就是說可以理解為是17、35的乙個縮影),17、35並不真實存在於非葉子節點中

那麼 b + 樹的查詢資料的過程又是怎樣的呢?

如圖所示,如果要查詢資料項29,那麼首先會把磁碟塊1由磁碟載入到記憶體(並不是將所有的磁碟塊(節點)一次性都加入到記憶體中),此時發生一次io(磁碟載入塊到記憶體的這個過程稱為一次 io),在記憶體中使用二分查詢確定29在17和35之間,鎖定磁碟塊1的p2指標,記憶體時間因為非常短(相比磁碟的io)可以忽略不計,通過磁碟塊1的p2指標的磁碟位址把磁碟塊3由磁碟載入到記憶體,發生第二次io,29在26和30之間,鎖定磁碟塊3的p2指標,通過指標載入磁碟塊8到記憶體,發生第三次io,同時記憶體中做二分查詢找到29,結束查詢,總計三次io。真實的情況是,3層的b+樹可以表示上百萬的資料(以 id 作為索引的話就是幾百萬個 id 也就是幾百萬條資料),如果上百萬的資料查詢只需要三次io(每乙個磁碟塊中儲存多個 id),效能提高將是巨大的,如果沒有索引,每個磁碟塊都要發生一次io(即使磁碟塊裡面可以裝多個資料項的縮影,但是由於單個磁碟塊的大小是 4k 或者 8k,這是由於作業系統限制的,所以單個磁碟塊中不可能儲存太多資料,所以磁碟塊的數目依然很多),顯然成本非常非常高。

b + 樹的性質

1、通過上面的查詢資料的過程,我們知道 io 次數取決於 b + 數的高度 h,假設當前資料表的資料為 n,每個磁碟塊的資料項的數量是 m,則有 h = ㏒(m+1) n,當資料量 n 一定的情況下,m 越大,h 越小;而 m = 磁碟塊的大小 / 資料項的大小,磁碟塊的大小也就是乙個資料頁的大小,是固定的,如果資料項佔的空間越小,資料項的數量越多,樹的高度越低。這就是為什麼每個資料項,即索引欄位要盡量的小(雖然資料項中儲存的是索引欄位的縮影,但是縮影的佔位元組數還是和真實的資料有關係的),比如 int 佔4位元組,要比 bigint8 位元組少一半。這也是為什麼 b + 樹要求把真實的資料放到葉子節點而不是內層節點,一旦放到內層節點,磁碟塊的資料項會大幅度下降,導致樹增高。當資料項等於1(乙個資料項占用乙個磁碟塊)時將會退化成線性表。

2、當 b+樹的資料項是復合的資料結構,比如(name,age,gender

)的時候,b +

樹是按照從左到右的順序來建立搜尋樹的,比如當(張三,20,f)這樣的資料來檢索的時候,b+

樹會優先比較 name 來確定下一步的搜尋方向,如果 name 相同再依次比較 age 和 gender

,最後得到檢索的資料;但當(20,f

)這樣的沒有 name 的資料來的時候,b+

樹就不知道下一步該查哪個節點,因為建立搜尋樹的時候 name 就是第乙個比較因子,必須要先根據 name 來搜尋才能知道下一步去**查詢。比如當(張三,f

)這樣的資料來檢索時,b+

樹可以用 name 來指定搜尋方向,但下乙個字段 age 的缺失,所以只能把名字等於張三的資料都找到,然後再匹配性別是f的資料了, 這個是非常重要的性質,即索引的最左匹配特性。

到這裡,大概了解了為什麼要使用索引和 mysql 中對於索引及資料的儲存的資料結構。

為什麼要使用blog

有哥們問我,你為什麼使用blog?我總結了一下,覺得有如下幾個原因。1對自己的督促 有了blog,就會經常記得寫點東西 就會經常翻翻網上的新文章,了解一下新技術,不至於迷失在忙碌的生活中 如果把自己的所感所想所學寫出了,自己對自己也會有個概念,不至於迷迷糊糊 還有,畢竟是掛在網上的文字,心中難免擔心...

為什麼要使用XML

xml 代表擴充套件標記語言 extensible markup language 是由 world wide web consortium w 3c 的 xml工作組定義的。這個工作組是這樣描述該語言的 擴充套件標記語言 xml 是 sgml 的子集,其目標是允許普通的 sgml 在web 上以目...

為什麼要使用Nginx?

有人說這些基準測試是不準確的,因為在這樣那樣的環境下,做的比較不一致。我傾向同意基準測試只是告訴了我們其中一部分情況,你能做的是消除偏見 有人見過所有人都同意乙個基準測試是公平的嗎?我是沒見過。我們投資的一些公司把web平台切換到nginx後,可以顯著的解決擴充套件問題。nginx明顯有效的實現了今...