資料庫的索引是怎麼工作的?

2021-10-21 13:29:27 字數 2595 閱讀 1737

譯文:

隨著資料量逐漸增大,索引變得十分重要,有人可以解釋一下索引到底是怎麼工作的嗎?

為什麼需要

當資料存在硬碟型的儲存裝置上時,它是以資料塊的形式儲存的。這些資料塊整個生命週期都會被訪問,進行原子訪問操作。磁碟的資料塊被規劃的和鍊錶差不多;兩者都含有資料的一部分,乙個指向下乙個節點(塊)的指標,同時它們的儲存也不是連續不斷的。

由於一定數量的資料只能被儲存在乙個區域,我們可以說搜尋乙個沒有排序的區域需要全域性搜尋也就是n/2資料庫的訪問量(平均),n指的是資料量的大小。如果這個區域是乙個non-key區域(例:不包括特殊的值)那麼全域性搜尋的資料訪問量必須是n。

對於已排序的資料區域,二分查詢可能會被用到,它的資料訪問量為 log2n,同時因為資料是non-key型的,一旦大的值被找到,剩下的另一半的資料是不需要被查詢的,因此它的效能提公升很顯著。

什麼是索引

索引是乙個對很多資料多個字段進行排序的方法。對乙個字段進行索引的同時會建立另乙個資料結構來儲存該字段的值,還有乙個指向對應資料的指標。然後這個索引結構會進行排序,使得二分查詢可以運用其中。

建立索引的劣勢是這些索引都需要硬碟上的額外空間,因為索引都被myisam引擎儲存在了表中。如果有很多字段新增了索引的話,那麼檔案系統的儲存空間很快就達到限制值。

是怎麼工作的

首先,我們先列出一張資料庫中的樣表

field name

data type

size on disk

id (primary key)

unsigned int

4 bytes

firstname

char(50)

50 bytes

lastname

char(50)

50 bytes

emailaddress

char(100)

100 bytes

例1 - 已排序vs未排序字段

給定乙個 r = 5,000,000 的資料樣本,每一條資料的大小為 r = 204 bytes,它們都被myisam引擎進行了排序,預設的資料塊大小為 b = 1024 bytes。每個塊就是 bfr = (b/r) = 1024/204 = 5 條資料。那麼這張表總共有 n = (r/bfr) = 5,000,000/5 = 1,000,000 條資料塊。

針對id進行全域性搜尋的複雜度平均大概是 n/2 = 500,000, 考慮到id欄位是乙個key欄位。因為id還是排序好了的,二分查詢的查詢複雜度大概是log2 1,000,000 = 19.93 = 20 個資料塊訪問量。我們可以立刻明顯的看出它的效能提公升。

而firstname既不是乙個key欄位也不是乙個已排序的字段,那二分查詢是不可能的,它的值也不是unique的,因此整張表的查詢可能要訪問 n = 1,000,000 個資料塊。這便是索引的目的。

考慮到乙個已索引的資料只包含了已索引欄位和乙個指向原資料的指標,這就確保了它會比它指向的多字段資料更小,所以索引本身會占用比原資料更小的磁碟空間,也導致了遍歷查詢時接入的資料塊的量更小。關於firstname的索引結構如下;

field name

data type

size on disk

firstname

char(50)

50 bytes

(record pointer)

special

4 bytes

例2 - 新增索引

給定乙個 r = 5,000,000 的含索引 r=54 bytes 的資料樣本,資料塊大小預設為 b = 1024 bytes. 乙個資料塊可以儲存的索引為 bfr = (b/r) = 1024/54 = 18 條記錄。所有的資料塊可以儲存 的索引資料量為 n = (r/bfr) = 5,000,000/18 = 277778 個。

現在對firstname欄位進行全域性搜尋,可以利用索引來增加效能。採用二分查詢的平均資料塊訪問量為 log2 277,778 = 18.08 = 19 次。為了找到實際的資料位址,會增加乙個資料塊的訪問也就是一共19+1 的資料塊訪問量,這比乙個沒有索引的1,000,000資料塊的查詢快多了。

什麼時候應該被使用

考慮到建立索引需要占用額外的磁碟空間(277,778個資料塊需要多占用28%的額外空間),太多的索引會導致檔案系統出現很多檔案大小限制的問題,選擇正確的索引變得十分重要。

既然索引只是為了加快查詢匹配資料的速度,如果只是為了輸出資料而建立索引的話純粹是一種磁碟空間浪費,而且為增加插入,刪除資料的時間,因此這種情況應該被避免。而且考慮到二分查詢的本質,資料的cardinality或者獨特性是很重要的。乙個cardinality為2的資料會將資料一分為二,而乙個cardinality為1,000的資料大概會被分成1,000塊。如果cardinality很低的話,查詢的效率會減少到全域性搜尋,當cardinality小於資料量的30%時,應該避免用索引來進行查詢優化,因為它只會浪費磁碟空間。

關於cardinality理解

在數學中,它的學名叫基數,具體含義可以自行查詢。

在資料庫中,cardinality反應了一列資料的獨特性大小,如果一列資料有很多重複的值,比如只有true或false,那麼它的cardinality就很低,但如果它的值有很高的獨特性(比如身份證號碼),那麼cardinality就很高。

什麼是資料庫索引,是怎麼工作的?

我們通過乙個簡單的例子來開始教程,解釋為什麼我們需要資料庫索引。假設我們有乙個資料庫表 employee,這個表有三個字段 列 分別是 employee name employee age 和employee address。假設表employee 有上千行資料。現在假設我們要從這個表中查詢出所有名...

什麼是資料庫索引,是怎麼工作的?(詳細介紹)

我們通過乙個簡單的例子來開始教程,解釋為什麼我們需要資料庫索引。假設我們有乙個資料庫表 employee,這個表有三個字段 列 分別是 employee name employee age 和employee address。假設表employee 有上千行資料。現在假設我們要從這個表中查詢出所有名...

資料庫索引是怎樣工作的?

我們通過乙個簡單的例子來開始教程,解釋為什麼我們需要資料庫索引。假設我們有乙個資料庫表 employee,這個表有三個字段 列 分別是 employee name employee age 和employee address。假設表employee 有上千行資料。現在假設我們要從這個表中查詢出所有名...