資料結構 索引怎麼選擇合適的資料結構?

2021-10-21 19:46:56 字數 2525 閱讀 4190

什麼是索引? 模擬我們要查詢一本很厚的書時,怎麼快速定位到需要的部分(或者快速縮小查詢範圍),索引就類似於書中的目錄。業務的抽象落地就是資料是怎麼儲存【資料結構】,怎麼根據儲存的資料結構獲取想要的資料【演算法】。可能(反正我是)剛開始理解索引的時候是從資料庫索引開始的,其實只要像mysql資料庫內部那樣可以通過b+樹快速定位、查詢想要的資料就是索引。redis中不論使用哪種資料節點,都需要使用key快速定位,全域性的索引就是雜湊表的資料結構。

如果我們想自己設計乙個業務系統的索引時?怎麼選擇底層的資料結構,可能兩眼一抹黑。其實可以基於業務梳理,業務特點,想幹什麼,需要提供什麼功能或者方法。 從候選的資料結構中進行賽選,能夠做索引的資料結構本身其實並不多,可供選擇的有:雜湊表、有序陣列、紅黑樹、跳表、b+樹(b樹)、位圖(布隆過濾器)等。

個人理解:需求梳理

->

功能(需要支援的方法)+ 效能

->

演算法 + 資料結構

比如:mysql為什麼選擇b+樹? 再比如:redis中的有序集合為什麼選擇跳表?(ps: 有序集合中所有的資料都小於24位元組,並且集合元素個數小於128個時,為了平衡時間空間複雜度,折中使用了壓縮列表)

1、梳理需求,redis需要支援5種資料型別,提供資料的多樣性選擇。有序集合(sorted sets)就是其中一種資料型別。

2、上面的需求,要實現有序陣列功能,再梳理一下需要支援的方法

1)、新增、刪除乙個資料; 查詢資料乙個資料;

2)、按照區間查詢資料,比如查詢 [12-45]的資料(與mysql 的between and一樣);

3)、迭代輸出有序序列。

3、基於上面的方法和一些限制(比如mysql是單執行緒,io型業務等,再進行權衡)

1)、資料結構本身讀寫效能要高,雜湊表(讀寫時間複雜度近似o(1))、有序陣列只適用於靜態資料。     讀寫時間複雜度都是o(logn)的紅黑樹、跳表、b+樹都可行。但是資料是儲存在記憶體中的,b+樹比較適合的是外部儲存(磁碟)。

2)、支援區間查詢,雜湊表、紅黑樹都不適合去檢查。 b+樹適合區間查詢,但是上面已經pass掉了。 到現在其實剩下的就是跳表了。

梳理完mysql選擇b+樹的過程,redis的有序集合選擇跳表的過程。梳理需求功能點和要支援的方法、可供選擇索引的資料結構的特點,是選擇索引的關鍵,下面進行專門梳理,讓自己選擇索引、資料結構時不那麼茫然。

資料是結構化還是非結構化

結構化資料:可以類似表一樣儲存到mysql等關係型資料庫中的資料;資料庫底層使用的是b樹、b+樹等。

資料是靜態還是動態的

靜態資料:不考慮新增刪除的效能,有序陣列就可以考慮;雜湊表等依賴陣列實現的樹結構,本身動態擴容時對效能本身是有影響的,當然也可以使用redis那樣的 漸進式rehash。

動態資料:需要資料結構本身新增、刪除的時維護資料特點的代價不能太高。 

索引是儲存在記憶體還是磁碟中,還是一部分在磁碟一部分在記憶體

如果資料儲存在磁碟中,我們就要考慮,記憶體計算定址的速度是納秒級別的,而磁碟定址的效率是毫秒級別的,差了上萬到幾十萬倍。開率該效能可能已經遠超資料結構本身。b+樹就是為了考慮資料庫儲存的資料將大量落在磁碟上,為了降低樹的高度,多路平衡查詢樹,mysql的b+樹預設1200路,將樹基本控制在4層內。

單隻查詢,還是區間查詢

基本待選擇作為索引的資料結構,單值查詢效率都是非常高的。只是需要支援快速區間查詢,基本就只有 跳表和b+樹(b樹)了。

可能需要對資料本身預先做處理等

其他非功能性需求,還需要考慮資料結構本身的空間複雜度不能過高,或高到不能接受;索引維護的成本問題,主要就是新增、刪除之後,還需要維持原資料結構的特點。

可供索引選擇的資料結構一般時間複雜度都比較低,或者至少查詢的時間複雜度比較低: 雜湊表、跳表、紅黑樹、b+樹(b樹)、有序陣列,點陣圖和布隆過濾器可以輔助。

雜湊表 新增、刪除、查詢的時間複雜度都接近o(1), 但是不支援區間查詢。新增、刪除操作時,需要考慮某一次進行動態擴容(縮容)的耗時較高,不能接受的話需要像redis一樣同時維護兩個陣列,漸進式rehash。 redis、mencache等 key value記憶體資料庫會使用雜湊表做索引。

紅黑樹 新增、刪除、查詢的時間複雜度為o(logn),也不適合區間查詢。非常適合用於記憶體中構建索引。 ext檔案系統中,使用紅黑樹對磁碟塊進行索引。

b+樹 新增、刪除、查詢的時間複雜度為o(logn),支援區間查詢、比較適合在磁碟中構建索引。 mysql中使用b+樹,oracle、mongodb總使用b樹構建索引。

跳表 新增、刪除、查詢的時間複雜度為o(logn),支援區間查詢,比較適合在記憶體中構建索引,空間複雜度可以控制在一定範圍內。 redis的有序集合使用跳表構建索引。

有序陣列 利用二分查詢的查詢的時間為o(logn),支援區間查詢。如果是一次構建多次查詢,或者基本就是靜態資料,可以選擇有序陣列作為索引。

布隆過濾器 在大資料量比較大的情況下,判斷資料是否存在可以使用布隆過濾器, 判斷其可能存在的資料,大概率是存在(小概率誤判不存在),判斷不存在的資料一點不存在。資料量大時記憶體佔用率非常低。

索引 資料結構

子元素比根元素大,放在右邊,反之亦然。如果資料從1開始遞增,依然使用二叉樹的話,二叉樹就會變成鍊錶結構 本質上是二叉樹,如果某一邊的子元素與另一邊的子元素相比超過二個,會發生自旋,一種平衡方式。也叫二叉平衡樹 在自增資料量很大的時候,樹的層數太高,查詢效率也會變低 葉節點具有相同的深度,葉節點的指標...

mysql 資料結構 Mysql索引資料結構

mysql索引資料結構 當慢查詢時,看sql是否走索引。索引的本質 索引是幫助mysql高效獲取資料的排好序的資料結構。mysql若不建立索引,查詢某條資料時則會逐行掃瞄,每掃瞄一行資料就會做一次磁碟io。b tree 葉節點具有相同的深度,葉節點的指標為空。所有索引元素不重複。葉節點中的資料索引從...

資料結構索引 InnoDB索引

我們知道,myisam索引檔案和資料檔案是分離的,索引檔案僅僅儲存了資料記錄的位址。在innodb中,資料檔案本身就是索引檔案,表檔案本身就是乙個按照b 樹組織的乙個索引結構,葉節點data儲存了完整的資料記錄,這個索引的key是資料表的主鍵,因此innodb表資料檔案本身就是主索引。上圖是inno...