1. 程式人生 > >MySQL索引(二):建索引的原則

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

在瞭解了索引的基礎知識及B+樹索引的原理後(如需複習請點[這裡](https://www.cnblogs.com/liang24/p/14094629.html)),這一節我們瞭解一下有哪些建索引的原則,來指導我們去建索引。 ## 建索引的原則 ### 1. 聯合索引 我們可能聽一些資料庫方面的專業人士說過:“把 Where 條件裡面的列都建上索引”,從而給每個列給每個列建獨立的索引,這個理解是非常錯誤的。 如果 Where 條件裡有多種組合的查詢條件,可以嘗試建聯合索引來減少索引數量,同時提升查詢效能。 ### 2. 覆蓋索引 普通索引查到主鍵後,回到主鍵索引搜尋的過程,稱為回表。 當使用普通索引查詢時,普通索引有我們所需結果的所有資訊(欄位),就可以直接提供查詢結果,而不需要回表。也就是說,在這個查詢裡,索引已經被“覆蓋了”查詢需求,稱為覆蓋索引。 ```mysql 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 mysql> create table orders ( ID int primary key, city varchar(16) NOT NULL )engine=InnoDB; ``` 一種方法是計算完整列的選擇性,並使字首的選擇性接近於完整列的選擇性。 計算完整列的選擇性: ```mysql mysql> SELECT COUNT(DISTINCT city)/COUNT(*) FROM orders; ``` 在同一個查詢中計算不同字首長度的選擇性: ```mysql 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 mysql> ALTER TABLE orders ADD KEY (city(7)); ``` ### 5. 選擇合適的索引順序 在聯合索引中,索引列的順序是按照從左到右逐列進行排序的。因此索引可以按照升序或降序進行掃描,以滿足精確符合列順序的 ORDERY BY、GROUP BY 和 DISTINCT 等子句的查詢需求。 因此聯合索引的列順序很重要。 如何選擇索引的列順序有一個經驗法則:將選擇性最高的列放到索引最前列。 這個經驗法則在某些場景下有用,但可能在另外場景下,可能就沒效了,這要根據具體情況進行分析。 ## 參考資料 - [高效能MySQL(第3版) : 第3版](https://book.douban.com/subject/23008813/) - [MySQL技術內幕 : InnoDB儲存引擎(第2版)](https://book.douban.com/subject/24708143/) - [05 | 深入淺出索引(下)](https://time.geekbang.org/column/articl