簡體   English   中英

為什么我們將 B+ 樹用於聚集索引而不是散列?

[英]Why we use B+ tree for clustered index rather than hashing?

在 MySQL InnoDB 或許多其他數據庫引擎中,主鍵是通過聚集索引實現的。 但是使用二級索引搜索后,引擎必須使用二級索引中提供的主鍵查找聚集索引(如果沒有覆蓋索引)。

InnoDB 使用 B+ 樹作為其聚集索引,它是一個搜索復雜度為O(log n)的結構,因此我們可以將過程總結如下:

  1. 使用聚集索引:一次,成本O(n)
  2. 使用二級索引:兩次。 第一次通過花費O(log n)獲得m條記錄的結果。 然后第二遍成本為m記錄中的每一個的O(log n) ,因此時間復雜度將為m*O(log n)

我知道在使用 hasing 時,搜索的時間復雜度可以降低到O(1) ,所以我想知道為什么這些數據庫引擎更喜歡使用 B+ 樹而不是 hasing 技術(例如構建 KV 存儲)? 是因為記錄存儲在磁盤上而不是 memory 中嗎?

同時,我還有一個問題,其他一些數據庫,比如 RocksDB,使用 KV 存儲而不是 B+ 樹。 他們為什么使用它?

編輯

我想讓這個問題更清楚。 我發現很多表格都是用auto increment PK 設計的,而不是使用具有實際意義的東西,比如電話號碼或 IP。 所以B+樹的優勢沒有得到充分發揮。 例如,B+ 樹擅長在范圍內搜索數據,但我在范圍內搜索auto increment PK 在實踐中很少見。

B樹索引的一個重要特性就是所謂的范圍掃描。 Hash 索引沒有這個特性。 舊的 MySQL 表引擎的名稱MyISAM提供了線索。 它代表索引順序訪問方法。 BTREE 索引的固有順序是一個主要特征。

如果我們有一個表credit ,例如,列credit_iduser_iddatestampamount ,我們可能會使用這個查詢。

SELECT SUM(amount) amount FROM credit 
 WHERE datestamp >= CURDATE() - INTERVAL 7 DAY
   AND datestamp <  CURDATE();

使用(日期戳(datestamp, amount)上的兩列 BTREE 索引 MySQL 可以隨機訪問索引 O(log n) 到第一個合格的日期戳,然后為每個連續的合格日期戳順序訪問它 O(1)。 並且,由於amount在索引中,MySQL 完全可以滿足從索引查詢。 (稱為 覆蓋索引)。 InnoDB 索引隱式包含主鍵列,即保存所有表數據的聚集索引的鍵。

大多數大型生產表都為它們定義了幾個覆蓋索引,選擇它們來加速在特定應用程序中花費最多時間的查詢。

我並不是說 HASH 索引沒有用。 離得很遠。 但很明顯,如果沒有 BTREE 索引,MySQL 的工作效率會低得多。

(InnoDB 引擎的代碼對插入具有自動遞增主鍵的行進行了許多優化。如果應用程序使用其他東西——比如隨機 guid——作為主鍵,它可能會破壞這些優化。)

高效的 hash 需要預先了解密鑰的類型、數量和分布。 加上處理沖突的復雜性(兩個鍵以相同的 hash 值結束)。 空間必須預先分配,並且空間可能太小並很快用完,或者太大導致大量資源浪費。

b-trees 在小的時候是有效的,並且可以增長到任何大小,只要有可用的磁盤空間。

您引用了操作的數量,但 b-trees 使用便宜的簡單比較,散列使用昂貴的復雜算法。 因此,要在 64,000 條記錄的數據庫中查找記錄的位置,進行七八次比較可能比計算 hash 值使用更少的 CPU。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM