索引的資料結構及其優化策略

2021-08-23 12:33:28 字數 3680 閱讀 3208

為什麼使用b+樹而不是紅黑樹作為索引?

一般來說,索引本身也很大,不可能全部儲存在記憶體中,因此索引往往以索引檔案的形式儲存的磁碟上。這樣的話,索引查詢過程中就要產生磁碟i/o消耗,相對於記憶體訪問,i/o訪問的消耗要高幾個數量級,索引的結構組織要儘量減少查詢過程中磁碟i/o的訪問次數。

磁碟往往不是嚴格按需讀取,而是每次都會預讀,即使只需要乙個位元組,磁碟也會從這個位置開始,順序向後讀取一定長度的資料放入記憶體。

由於磁碟順序讀取的效率很高(不需要尋道時間,只需很少的旋轉時間),因此對於具有區域性性的程式來說,預讀可以提高i/o效率。

資料庫系統的設計者巧妙的利用了磁碟預讀原理,將乙個結點的大小設為等於乙個頁面,這樣每個結點只需要一次i/o就可以完全載入。紅黑樹實際上是一顆二叉樹,即使邏輯上很近的結點(父子結點)物理上可能離得很遠,無法利用區域性性原理。而且如果儲存相同數量的資料,紅黑樹的高度要比b+數高的多,所以查詢效率明顯比b+tree差得多。

雖然b樹解決了磁碟io問題,但是b樹的非葉子節點也儲存著資料,所以沒有解決元素遍歷效率低下的問題,b+樹只要遍歷葉子節點就可以實現整棵樹的遍歷。而且在資料庫中基於範圍的查詢是非常頻繁的,而b樹不支援這樣的操作(或者說效率太低)。

一般在資料庫系統或檔案系統中使用的b+tree結構都在經典 b+tree的基礎上進行了優化,增加了順序訪問指標,每個葉子結點增加乙個指向相鄰葉子結點的指標,目的是為了提高區間訪問的效能只需順著結點和指標順序遍歷就可以一次性訪問到所有資料結點,極大提到了區間查詢效率。

索引優化

聯合索引及最左字首原理

聯合索引(復合索引)

相對於一般索引只有乙個字段,聯合索引可以為多個字段建立乙個索引。它的原理也很簡單,比如,我們在(a,b,c)欄位上建立乙個聯合索引,則索引記錄會首先按照a欄位排序,然後再按照b欄位排序然後再是c欄位,因此,聯合索引的特點就是:

第乙個字段一定是有序的當第乙個字段值相等的時候,第二個欄位又是有序的,比如下表中當a=2時所有b的值是有序排列的,依次類推,當同乙個b值得所有c欄位

是有序排列的

| a | b | c |

| 1 | 1 | 3 |

| 1 | 2 | 2 |

| 1 | 4 | 4 |

| 2 | 3 | 5 |

| 2 | 4 | 4 |

| 2 | 4 | 6 |

| 2 | 5 | 5 |

其實聯合索引的查詢就跟查字典是一樣的,先根據第乙個字母查,然後再根據第二個字母查,或者只根據第乙個字母查,但是不能跳過第乙個字母從第二個字母開始查。這就是所謂的最左字首原理。

字首索引

字首索引就是 用列的字首代替整個列作為索引key,當字首長度合適時,可以做到既使得字首索引的選擇性接近全列索引,同時因為索引key變短而減少了索引檔案的大小和維護開銷。

一般來說以下情況可以使用字首索引:

字串列(varchar,char,text等),需要進行全欄位匹配或者前匹配。也就是=『***』 或者 like 『***%』

字串本身可能比較長,而且前幾個字元就開始不相同。

比如我們對中國人的姓名使用字首索引就沒啥意義,

因為中國人名字都很短,另外對收件位址使用字首索引也不是很實用,因為一方面收件位址一般都是以xx省開

頭,也就是說前幾個字元都是差不多的,而且收件位址進行檢索一般都是like 』%***%』,不會用到前匹配。

相反對外國人的姓名可以使用字首索引,因為其字元較長,而且前幾個字元的選擇性比較高。同樣電子郵件也是

乙個可以使用字首索引的字段。

前一半字元的索引選擇性就已經接近於全字段的索引選擇性。如果整個欄位的長度為20,索引選擇性為0.9,

而我們對前10個字元建立字首索引其選擇性也只有0.5,那麼我們需要繼續加大字首字元的長度,但是這個時候

字首索引的優勢已經不明顯,沒有太大的建字首索引的必要了。

mysql 字首索引能有效減小索引檔案的大小,提高索引的速度。但是字首索引也有它的壞處:mysql 不能在 order by 或 group by 中使用字首索引,也不能把它們用作覆蓋索引(covering index)。

索引優化策略

最左字首匹配原則,上面講到了

1.主鍵外檢一定要建索引對 where,on,group by,order by 中出現的列使用索引盡量選擇區分度高的列作為索引,區分度的公式是count(distinct col)/count(*),表示欄位不重複的比例,比例越大我們掃瞄的記錄數越少,唯一鍵的區分度是1,而一些狀態、性別字段可能在大資料面前區分度就是0

2.對較小的資料列使用索引,這樣會使索引檔案更小,同時記憶體中也可以裝載更多的索引鍵

3.索引列不能參與計算,保持列「乾淨」,比如from_unixtime(create_time) = 』2014-05-29』就不能使用到索引,原因很簡單,b+樹中存的都是資料表中的字段值,但進行檢索時,需要把所有元素都應用函式才能比較,顯然成本太大。所以語句應該寫成create_time =unix_timestamp(』2014-05-29』);

4.為較長的字串使用字首索引盡量的擴充套件索引,不要新建索引。比如表中已經有a的索引,現在要加(a,b)的索引,那麼只需要修改原來的索引即可不要過多建立索引, 權衡索引個數與dml之間關係,dml也就是插入、刪除資料操作。這裡需要權衡乙個問題,建立索引的目的是為了提高查詢效率的,但建立的索引過多,會影響插入、刪除資料的速度,因為我們修改的表資料,索引也需要進行調整重建

5.對於like查詢,」%」不要放在前面。

select * from houdunwang where uname like' 後盾 %' --  走索引

select * from houdunwang where uname like "% 後盾 %" --  不走索引

6.查詢where條件資料型別不匹配也無法使用索引

字串與數字比較不使用索引;

create table a ( a char(10));

explain select * from a where a ="1" – 走索引

explain select * from  a where  a =1 – 不走索引

7.正規表示式不使用索引,這應該很好理解,所以為什麼在sql中很難看到regexp關鍵字的原因。

既然索引可以加快查詢速度,那麼是不是只要是查詢語句需要,就建上索引?

索引雖然加快了查詢速度,但索引也是有代價的:索引檔案本身要消耗儲存空間,同時索引會加重插入、刪除和修改記錄時的負擔,另外,mysql在執行時也要消耗資源維護索引,因此索引並不是越多越好.例如一兩千條甚至只有幾百條記錄的表,沒必要建索引,讓查詢做全表掃瞄就好了。

什麼情況下需要建立索引?

1.哪些情況需要建立索引

1).主鍵自動建立唯一索引

2).頻繁作為查詢查詢條件的字段應該建立索引

3).查詢中與其它表關聯的字段,外來鍵關係建立索引

4).頻繁更新的字段不適合建立索引

5).where條件裡用不到的字段不建立索引

6).單鍵/組合索引的選擇問題(在高併發下傾向建立組合索引)

7).查詢中排序的字段,排序欄位若通過索引去訪問將大大提高排序速度

8).查詢中統計或者分組字段

2.哪些情況不要建立索引

1).表記錄太少

2).經常增刪改的表(因為不僅要儲存資料,還要儲存一下索引檔案)

3).資料重複且分布平均的表字段,因此應該只為最經常查詢和最經常排序的資料列建立索引。

mysql的索引及其資料結構

mysql使用中,當業務量過大,通常會通過建立索引增加效率。兩種索引 索引其實是一種資料結構,在mysql中主要有兩種 hash索引和b tree 索引。兩者中hash索引是無序的,不支援範圍查詢,只適合等值查詢。b 樹是一種多路平衡查詢樹,所以他的節點是有序的 左子節點小於父節點 父節點小於右子節...

Mysql索引的資料結構及索引優化

索引的本質 是幫助mysql高效獲取資料的排好序的資料結構。索引資料結構 1 二叉樹 儲存資料的時候是乙個鍊錶,如果要查詢0006的話要查詢6次,如果是全表掃瞄的話也得查詢6次。弊端 二叉樹的查詢效率很低。2 紅黑樹 儲存資料的時候會自旋,如果要查詢0006的話只需要查詢3次。如果是全表掃瞄或二叉樹...

資料結構 氣泡排序以及其優化

我以前一直對冒牌排序不以為然,作為最容易寫出來的排序.直到前兩天我被人問到乙個問題,讓我把普通的氣泡排序最好的時間複雜度 優化到o n 當然氣泡排序最壞時間複雜度o n 2 這個沒有辦法改變.我們只能盡量優化它的過程讓它少走幾次迴圈.其實仔細做起來,我 在寫程式有時候還是太片 面了不能夠考慮到最優的...