首頁 > 軟體

MySQL索引結構詳細解析

2022-03-01 19:01:48

簡介

在資料之外,資料庫系統還維護著滿足特定查詢演演算法的資料結構,這些資料結構以某種方式參照(指向)資料,這樣就可以在這些資料結構上實現高階查詢演演算法。這種資料結構,就是索引。

一般來說索引本身也很大,不可能全部儲存在記憶體中,因此索引往往以索引檔案的形式儲存的磁碟上。

優點:

1、類似大學圖書館建書目索引,提高資料檢索的效率,降低資料庫的IO成本。

2、通過索引列對資料進行排序,降低資料排序的成本,降低了CPU的消耗。

缺點:

1、雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對錶進行INSERT、UPDATE和DELETE。因為更新表時,MySQL不僅要儲存資料,還要儲存一下索引檔案。每次更新新增了索引列的欄位,都會調整因為更新所帶來的鍵值變化後的索引資訊。

2、實際上索引也是一張表,該表儲存了主鍵與索引欄位,並指向實體表的記錄,所以索引列也是要佔用空間的

索引舉例:(用樹結構做索引)

左邊是資料表,一共有兩列七條記錄,最左邊的是資料記錄的實體地址。

為了加快Col2的查詢,可以維護一個右邊所示的二叉查詢樹,每個節點分別包含索引鍵值和一個指向對應資料記錄實體地址的指標,這樣就可以運用二叉查詢在一定的複雜度內獲取到相應資料,從而快速的檢索出符合條件的記錄。

索引結構(樹)

如何通過索引加快資料庫表的查詢速度呢?為了方便講解,我們限定於資料庫表只包含下面這樣兩個查詢需求:

1、select* from user where id=1234;

2、select *from user where id>1234 and id<2345;(按區間)

為什麼用樹,而不用雜湊表

雜湊表按值查詢的效能很好,時間複雜度是O(1),但它不能支援按照區間快速查詢資料,因此無法滿足要求。同理,儘管平衡二叉查詢樹查詢效能很高,時間複雜度為O(logn),而且對樹進行中序遍歷,可以輸出有序的資料序列,但也無法滿足按照區間快速查詢資料的需求。

為了支援按照區間快速查詢資料,我們對二叉查詢樹進行改造,將二叉查詢樹的葉子節點用連結串列串起來,如果要查詢某個區間的資料,只需要用區間的起始值,在樹中進行查詢,當定位到有序連結串列中的某個節點之後,再從這個節點開始順著有序連結串列往後遍歷,直到有序連結串列中的節點資料值大於區間終止值為止。

又因為樹上的很多操作的時間複雜程度與樹的高度成正比,降低的樹的高度,就能減少磁碟IO操作。因此我們把索引構建成m叉樹(m>2),詳細介紹可看後文。

BTree索引

在介紹B+樹之前,先來了解一下B樹。

1、初始化介紹

一顆b樹,淺藍色的塊我們稱之為一個磁碟塊,可以看到每個磁碟塊包含幾個資料項(深藍色所示)和指標(黃色所示),如磁碟塊1包含資料項17和35,包含指標P1、P2、P3。P1表示小於17的磁碟塊,P2表示在17和35之間的磁碟塊,P3表示大於35的磁碟塊。

注意:

真實的資料只存在於葉子節點,即3、5、9、10、13、15、28、29、36、60、75、79、90、99。(而且是多條資料組成的資料區間:3~ 5,… … ,90~ 99)

非葉子節點不儲存真實的資料,只儲存指引搜尋方向的資料項,如17、35並不真實存在於資料表中。

2、查詢過程

如果要查詢資料項29,那麼首先會把磁碟塊1由磁碟載入到記憶體,此時發生一次IO,在記憶體中用二分查詢確定29在17和35之間,鎖定磁碟塊1的P2指標,記憶體時間因為非常短(相比磁碟的IO)可以忽略不計,通過磁碟塊1的P2指標的磁碟地址把磁碟塊3由磁碟載入到記憶體,發生第二次IO,29在26和30之間,鎖定磁碟塊3的P2指標,通過指標載入磁碟塊8到記憶體,發生第三次IO,同時記憶體中做二分查詢找到29,結束查詢,總計三次IO。

B+Tree索引

B+樹和B樹類似,B+樹是B樹的改進版。 即:m叉查詢樹與有序連結串列構建成的樹就是B+樹,也就是要儲存的樹索引

如圖:B+樹和B樹的主要區別有以下兩點:

1、B+樹的葉子節點用連結串列來串聯。 查詢某個區間的資料,只需要用區間的起始值,在樹中進行查詢,當定位到有序連結串列中的某個節點之後,再從這個節點開始順著有序連結串列往後遍歷,直到有序連結串列中的節點資料值大於區間終止值為止。

2、B+樹中的任何節點都不儲存真實資料,只是用來索引。 B樹直接通過葉子節點獲取到資料;而B+樹每個葉子節點儲存資料行的鍵值和地址資訊,當查詢到某個葉子節點時,通過葉子節點的地址找到真實的資料資訊。

聚簇索引與非聚簇索引

聚簇索引並不是一種單獨的索引型別,而是一種資料儲存方式。 術語‘聚簇’表示資料行和相鄰的鍵值聚簇的儲存在一起。

聚簇索引的好處:

按照聚簇索引排列順序,查詢顯示一定範圍資料的時候,由於資料都是緊密相連,資料庫不不用從多個資料塊中提取資料,所以節省了大量的io操作。

聚簇索引的限制:

1、對於mysql資料庫目前只有innodb資料引擎支援聚簇索引,而Myisam並不支援聚簇索引。

2、由於資料物理儲存排序方式只能有一種,所以每個Mysql的表只能有一個聚簇索引。一般情況下就是該表的主鍵。

3、為了充分利用聚簇索引的聚簇的特性,所以innodb表的主鍵列儘量選用有序的順序id,而不建議用無序的id,比如uuid這種。

如下圖,左側的索引就是聚簇索引,因為資料行在磁碟的排列和索引排序保持一致。

索引分類

單值索引

即一個索引只包含單個列,一個表可以有多個單列索引

隨表一起建索引:
CREATE TABLE customer (
id INT(10) UNSIGNED  AUTO_INCREMENT ,
customer_no VARCHAR(200),
customer_name VARCHAR(200),
PRIMARY KEY(id),
KEY (customer_name)
);
 
單獨建單值索引:
CREATE  INDEX idx_customer_name ON customer(customer_name); 
 
刪除索引:
DROP INDEX idx_customer_name  on customer;

唯一索引

索引列的值必須唯一,但允許有空值

隨表一起建索引:
CREATE TABLE customer (
id INT(10) UNSIGNED  AUTO_INCREMENT ,
customer_no VARCHAR(200),
customer_name VARCHAR(200),
  PRIMARY KEY(id),
  KEY (customer_name),
  UNIQUE (customer_no)
);
  
單獨建唯一索引:
CREATE UNIQUE INDEX idx_customer_no ON customer(customer_no); 
 
刪除索引:
DROP INDEX idx_customer_no on customer ;

主鍵索引

設定為主鍵後資料庫會自動建立索引,innodb為聚簇索引

隨表一起建索引:
CREATE TABLE customer (
id INT(10) UNSIGNED  AUTO_INCREMENT ,
customer_no VARCHAR(200),
customer_name VARCHAR(200),
  PRIMARY KEY(id) 
);
   
CREATE TABLE customer2 (
id INT(10) UNSIGNED   ,
customer_no VARCHAR(200),
customer_name VARCHAR(200),
  PRIMARY KEY(id) 
);
 
 單獨建主鍵索引:
ALTER TABLE customer 
 add PRIMARY KEY customer(customer_no);  
 
刪除建主鍵索引:
ALTER TABLE customer 
 drop PRIMARY KEY ;  
 
修改建主鍵索引:
必須先刪除掉(drop)原索引,再新建(add)索引

複合索引

即一個索引包含多個列

隨表一起建索引:
CREATE TABLE customer (
id INT(10) UNSIGNED  AUTO_INCREMENT ,
customer_no VARCHAR(200),
customer_name VARCHAR(200),
  PRIMARY KEY(id),
  KEY (customer_name),
  UNIQUE (customer_name),
  KEY (customer_no,customer_name)
);
 
單獨建索引:
CREATE  INDEX idx_no_name ON customer(customer_no,customer_name); 
 
刪除索引:
DROP INDEX idx_no_name  on customer ;

效能分析

索引建立場景

哪些情況需要建立索引

1、主鍵自動建立唯一索引

2、頻繁作為查詢條件的欄位應該建立索引

3、查詢中與其它表關聯的欄位,外來鍵關係建立索引

4、單鍵/組合索引的選擇問題, 組合索引價效比更高

5、查詢中排序的欄位,排序欄位若通過索引去存取將大大提高排序速度

6、查詢中統計或者分組欄位

哪些情況不要建立索引

1、表記錄太少

2、經常增刪改的表或者欄位 原因:提高了查詢速度,同時卻會降低更新表的速度,如對錶進行INSERT、UPDATE和DELETE。因為更新表時,MySQL不僅要儲存資料,還要儲存一下索引檔案

3、Where條件裡用不到的欄位不建立索引

4、過濾性不好的不適合建索引

到此這篇關於MySQL索引 詳細解析的文章就介紹到這了,更多相關MySQL 索引內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com