MySQL索引(二):建索引的原則

大雜草發表於2020-12-07

在瞭解了索引的基礎知識及B+樹索引的原理後(如需複習請點這裡),這一節我們瞭解一下有哪些建索引的原則,來指導我們去建索引。

建索引的原則

1. 聯合索引

我們可能聽一些資料庫方面的專業人士說過:“把 Where 條件裡面的列都建上索引”,從而給每個列給每個列建獨立的索引,這個理解是非常錯誤的。

如果 Where 條件裡有多種組合的查詢條件,可以嘗試建聯合索引來減少索引數量,同時提升查詢效能。

2. 覆蓋索引

普通索引查到主鍵後,回到主鍵索引搜尋的過程,稱為回表。

當使用普通索引查詢時,普通索引有我們所需結果的所有資訊(欄位),就可以直接提供查詢結果,而不需要回表。也就是說,在這個查詢裡,索引已經被“覆蓋了”查詢需求,稱為覆蓋索引。

mysql> create table T (
ID int primary key,
k int NOT NULL DEFAULT 0, 
s varchar(16) NOT NULL DEFAULT '',
index k(k))
engine=InnoDB;

select ID from T where k between 3 and 5

上面的例子中,k索引樹上已經包括了ID的值,就不需要回表了。

由於覆蓋索引可以減少樹的搜尋次數,顯著提升查詢效能,所以使用覆蓋索引是一個常用的效能優化手段。

在使用覆蓋索引時,要注意如果需要返回的欄位較多,就要權衡空間和時間。因為覆蓋索引要覆蓋較多欄位就需要更多的空間。

3. 最左字首原則

假設我們有2個欄位,例如身份證號和地址,現在有三種查詢需求:按身份證號查詢、按地址查詢,以及按身份證號和地址查詢。

如果每種需要都要建立一個索引,就顯得有利浪費。

從上一篇文章裡,我們瞭解到B+樹的特點是有序的,因此我們可以只建立兩個索引即滿足上面的三種需求,分別是(身份證號,地址)和(地址)。這就是B+樹索引的“最左字首”原則。

在建立聯合索引的時候,如何安排索引內的欄位順序:

  1. 第一原則是,如果通過調整順序,可以少維護一個索引,那麼這個順序往往就是需要優先考慮採用的。
  2. 第二原則是,空間。當兩個欄位存在一個明顯比另一個大時,例如name和age,明顯name要比age要大,此時應該建一個(name,age)的聯合索引和一個(age)的單欄位索引。

4. 字首索引和索引選擇性

有時候需要索引很長的字元列,這會讓索引變得大且慢。一種策略是模擬雜湊索引。

通常可以索引開始的部分字元,這樣可以大大節約索引空間,從而提高索引效率。但這樣也會降低索引的選擇性。

索引的選擇性指,不重複的索引值(也稱為基數,cardinality)和資料表的記錄總數(T)的比值,範圍從1/T到1之間。

如何確定字首索引的長度及建立字首索引

假設有個訂單表,其中有包括城市名稱的欄位(city,且城市名稱為英文),下面來介紹一下如何確定字首索引的長度。

mysql> create table orders (
ID int primary key,
city varchar(16) NOT NULL
)engine=InnoDB;

一種方法是計算完整列的選擇性,並使字首的選擇性接近於完整列的選擇性。

計算完整列的選擇性:

mysql> SELECT COUNT(DISTINCT city)/COUNT(*) FROM orders;

在同一個查詢中計算不同字首長度的選擇性:

mysql> SELECT COUNT(DISTINCT LEFT(city, 3))/COUNT(*) AS sel3,
        COUNT(DISTINCT LEFT(city, 4))/COUNT(*) AS sel4,
        COUNT(DISTINCT LEFT(city, 5))/COUNT(*) AS sel5,
        COUNT(DISTINCT LEFT(city, 6))/COUNT(*) AS sel6,
        COUNT(DISTINCT LEFT(city, 7))/COUNT(*) AS sel7
    FROM orders;

建立字首索引的方法:

mysql> ALTER TABLE orders ADD KEY (city(7));

5. 選擇合適的索引順序

在聯合索引中,索引列的順序是按照從左到右逐列進行排序的。因此索引可以按照升序或降序進行掃描,以滿足精確符合列順序的 ORDERY BY、GROUP BY 和 DISTINCT 等子句的查詢需求。

因此聯合索引的列順序很重要。

如何選擇索引的列順序有一個經驗法則:將選擇性最高的列放到索引最前列。

這個經驗法則在某些場景下有用,但可能在另外場景下,可能就沒效了,這要根據具體情況進行分析。

參考資料

相關文章