我們都知道資料庫的索引是用來提公升檢索速度的,但是索引究竟內部是怎麼工作的呢,就來說說這個話題8
索引就像書的目錄一樣,幫助我們更快的查詢到我們需要的資料。
索引的種類有很多種,接下來主要介紹三種常見,也比較簡單的資料結構,分別是雜湊表,有序陣列和搜尋樹。
然後從使用的角度分析一下,三者的區別:
雜湊表是一種kv儲存資料的形式,只要輸入待查詢的值,比如說是key,就可以找到value。
但如果多個k對應乙個v,那麼就會拉出乙個鍊錶。
那麼我們該如何在這種情況下,找到我們需要的那個v呢,可以看如下解釋。
假如有一張表,只有身份證號和姓名,需要根據身份證號找到姓名
這時候我們發現,id-card-n2和id-card-n4計算出的雜湊值都為n,並且n對應著一張鍊錶,那麼,假如我們要利用id-card-n2找出name2,該怎麼辦呢?
首先,將id-card-n2通過雜湊函式計算出n,然後按照順序遍歷找到user2。
有序雜湊,插入不方便,區間查詢方便,無序雜湊,插入方便(指的是順延插入),區間查詢不方便。
所以,雜湊表這種結構適用於等值查詢的場景。
如果以上的情況,我們用有序陣列實現的話,示意圖如下:
假設身份證賬號沒有重複,陣列按照底層去儲存,如果要查詢id-card-n2對應的名字,用二分法就可以查詢到,這個時間複雜度是logn、
並且這個索引結構支援範圍查詢。而且查詢效率也是相當高的。但是如果插入,就很麻煩,因為每乙個都需要往後瞬移乙個單位。
所以,有序陣列只能進行靜態儲存引擎,就是那種不會修改的資料。
二叉搜尋樹是非常經典的資料結構,也用上面的例子,效果如下:
二叉搜尋樹的特點是:每個節點的左兒子小於父節點,父節點又小於右兒子。
當然為了維持o(log(n))的查詢複雜度,你就需要保持這棵樹是平衡二叉樹。為了做這個保證,更 新的時間複雜度也是o(log(n))。
為了能夠讓乙個查詢更少的讀取總儲存,應該查詢的時候訪問更少的資料塊,所以就不能使用二叉樹,而是多叉樹,至於多少叉,取決於資料塊的大小,但是總體都滿足大小從左往右遞增。
以innodb的乙個整數字段索引來說,n差不多是1200,當樹高為4的時候,就可以儲存1200的3次方個值,但是考慮到樹根 是在記憶體的,所以訪問速度相當快,只需要訪問三次硬碟。
在mysql中,索引是在儲存引擎層實現的,所以沒有統一的索引標準,即不同儲存引擎的索引方式是不同的,以下以常用的innodb來說一下。
在innodb中,表都是根據主鍵順序以索引的形式發放的,這種儲存形式的表稱為索引組織表。
innodb使用了b+樹索引模型,所以資料都是儲存在b+樹的。
每乙個innodb索引都有乙個b+樹。
假設,我們有乙個主鍵列為id的表,表中有字段k,並且在k上有索引。
建表語句如下:
mysql>
create
table t3(
id int
unique
key,
k int
notnull
, name varchar(16
),index
(k))
engine
=innodb
;
query ok,
0rows affected (
0.03 sec)
然後插入語句
mysql>
insert
into t3 (id,k,name)
values
(100,1
,'r1');
query ok,
1row affected (
0.00 sec)
mysql>
insert
into t3 (id,k,name)
values
(200,2
,'r2'
);
query ok,
1row affected (
0.09 sec)
mysql>
insert
into t3 (id,k,name)
values
(300,3
,'r3');
query ok,
1row affected (
0.00 sec)
mysql>
insert
into t3 (id,k,name)
values
(500,5
,'r4');
query ok,
1row affected (
0.00 sec)
mysql>
insert
into t3 (id,k,name)
values
(600,6
,'r5'
);
query ok,
1row affected (
0.01 sec)
兩棵樹的示例圖如下:
可從圖看出,根據葉子節點的內容,索引型別分為主鍵索引和非主鍵索引。
主鍵索引的葉子結點儲存整行資料。
非主鍵索引的葉子結點內容是主鍵的值。
那麼,基於主鍵索引和普通索引的查詢有什麼區別?
也就是說,基於非主鍵索引的查詢需要多掃瞄一棵索引樹。
b+樹為了維護索引的有序性,在插入新值的時候需要做必要的維護。如果插入的新id=700,則只需要在r5後面插入即可,如果id=400,就需要讓r5往後退乙個流出位置。
更加糟糕的情況是,如果資料頁已經滿了,就得需要申請乙個新的資料頁,那麼這個過程就叫做頁**,效能會降低很多。
除了效能,還會影響資料頁的利用率,原本是放在乙個頁資料,現在分到兩個頁中,整體利用率降低50%。
既然有頁**也會有頁合併,當相鄰兩個頁由於刪除了資料,利用率很低之後,會將資料頁做合併。
在建表的時候,這樣來定義自增主鍵。
not null primary key auto_increment
插入的時候不用指定自增的主鍵。
從業務角度去考慮,如果你的表內有除了自增主鍵以外的唯一字段,那麼是用自增主鍵還是用唯一欄位呢。
由於每個非主鍵索引的葉子節點上都是主鍵的值,如果用唯一字段,那麼每個二級索引的葉子節點占用n(具體長度由唯一字段長度決定)位元組,如果用整形做主鍵,則只需要4位元組,如果是長整型就需要8位元組。
顯然,主鍵長度越小,普通索引占用空間就越少。
所以,從效能和儲存空間方面考量,自增主鍵往往是更合理的選擇。
04 深入淺出索引(上)
1.索引的作用 提高資料查詢效率,就像書的目錄一樣。2.常見索引模型 雜湊表 有序陣列 搜尋樹 3.雜湊表 鍵 值 key value 4.雜湊思路 把值放在陣列裡,用乙個雜湊函式把key換算成乙個確定的位置,然後把value放在陣列的這個位置 5.雜湊衝突的處理辦法 鍊錶 6.雜湊表適用場景 只有...
03 深入淺出索引上下
三種索引 全文索引,雜湊索引,b 樹索引 索引維護 頁 隨機插入,向右 索引的選擇 身份證id or 自增主鍵 效能 儲存。效能 身份證id,是隨機插入,頁 是中間 可能會造成一定的儲存浪費,次數頁比較多。但是自增主鍵,只有頁滿才會將新點 到下乙個頁,效率是最高的。儲存 乙個b 樹節點,儲存的身份證...
MySQL學習 3 深入淺出索引(上)
innodb的索引模型 參考資料 寫在後面 環境 mysql5.7.24,for linux glibc2.12 x86 64 簡單來說,索引的出現其實就是為了提高資料查詢 的效率,就像書的目錄一樣。對於資料庫的表而言,索引其實就是它的 目錄 用於提高讀寫效率的資料結構有很多,以下介紹三種常見 也比...