1. 程式人生 > >建立高效能mysql索引

建立高效能mysql索引

1 索引基礎

1.1 索引型別

B-tree索引(具體性質參見B-tree資料結構):所有值按照順序儲存,每一個葉子頁到根的距離相同,索引的順序很重要。有索引key(last_name,first_name,dob)。可查詢如下型別:

  • 全值匹配:如Cuba Allen,1960-01-01

  • 匹配最左字首:如Allen,即只使用索引的第一列。

  • 匹配列字首:查詢所有以J開頭的姓的人,使用索引第一列

  • 匹配範圍值:姓在Allen和BarryMore之間的人,使用索引第一列。

  • 精確匹配某一列並範圍匹配另外一列:第一列全匹配,第二列範圍匹配。

  • 只訪問索引的查詢

B-tree索引的限制:

  • 如果不是按照索引的最左列開始查詢,則無法使用索引。如索引無法查詢名字為bill的人,也無法查詢特定生日的人,也無法查詢姓氏以某個字母結尾的人。

  • 不能跳過索引中的列。索引無法用於查詢姓為smith並且在某個特定日期出生的人,如不指定名(first_name),則mysql只能使用索引第一列。

  • 如果查詢中有某個列的範圍查詢,則其右邊所有列都無法使用索引優化查詢。如有查詢WHERE last_name=’Smith’ AND frist_name LIKE ‘J%’ AND dob=’1976-01-01’。這個查詢只能使用索引的前兩列。

雜湊索引

基於雜湊表實現,只有精確匹配索引所有列的查詢才有效。在mysql中,只有momery引擎顯示支援雜湊索引。

空間資料索引(R-Tree)

MyISAM表支援空間索引,可以用作地理資料索引,這類索引無需字首查詢。

全文索引

是一種特殊的索引,它查詢的時文字中的關鍵詞,而不是直接比較索引中的值。

2 索引優點

  • 大大減少了伺服器需要掃描的資料量

  • 幫助伺服器避免排序和臨時表

  • 可以將隨機io變為順序io。

非常小的表,大部分情況下簡單的全表掃描更高效。中到大型表,索引非常有效。特大型表需要使用分割槽技術。

3 高效能的索引策略

3.1 獨立的列

始終將索引列單獨放在比較符號的一側。

3.2 字首索引和索引選擇性

當索引很長的字元列,會讓索引變的大且慢。一個策略是模擬雜湊索引,還可以索引開始的部分字元,這樣可以大大節約索引空間,提高索引效率。一般當前綴長度達到7的時候,再增加字首長度,選擇性提升的幅度已經很小了。

建立字首索引:alter table sakila.city_demo add key(city(7))

字首索引的缺點:無法使用字首索引做order by和group by,也無法使用字首索引做覆蓋掃描。

3.3 多列索引

如索引:key(last_name,first_name,dob)

3.4 選擇合適的索引列順序

正確的順序依賴於使用該索引的查詢,並且同時需要考慮如何更好地滿足排序和分組的需要。在一個多列btree索引中,索引列的順序意味著索引首先按照最左列進行排序,其次是第二列,等等。多列索引的列順序至關重要。經驗做法:將選擇性最高的列放在索引最前列。或者使用pt-query-digest工具進行分析。

3.5 聚簇索引

聚簇索引並不是一種單獨的索引型別,而是一種資料儲存方式,一個表只能有一個聚簇索引。InnoDB將通過逐漸聚集資料,如果沒有定義主鍵,InnoDB會選擇一個唯一的非空索引代替。如果沒有這樣的索引,InnoDB會隱式定義一個主鍵來作為聚簇索引。使用InnoDB時應該儘可能地按主鍵順序插入資料,並且儘可能地使用單調增加的聚簇鍵的值來插入新行。

在InnoDB中,聚簇索引就是表,InnoDB的二級索引和聚簇索引很不同。InnoDB二級索引的頁子節點中儲存的不是“行指標”,而是主鍵值,並以此作為指向行的“指標”。

主索引:建立表啟用後由系統自動建立的,不能修改

二級索引:自己建立的索引

3.6 覆蓋索引

如果一個索引包含所有需要查詢的欄位的值,我麼就稱之為覆蓋索引。覆蓋索引能夠極大提高效能,只需要掃描索引而無須回表。覆蓋索引必須要儲存索引列的值,所以mysql只能使用btree索引做覆蓋索引。

錯誤示例:select * from products where actor=’sean carrey’ and title like ‘%apollo%’\G

這裡索引無法覆蓋該查詢:1查詢從表中選擇了所有得咧,而沒有任何索引覆蓋了所有得列。2 mysql不能在索引中執行like操作,只能在索引中做最左匹配字首匹配。

優化:select * from products join (select prod_id from products where actor=’sean carrey’ and title like ‘%apollo%’) as t1 on (t1.prod_id=products.prod_id)\G

3.7 使用索引掃描來做排序

如果explain出來的type列值為’index’,則說明mysql使用了索引掃描來做排序。

只有當索引的列順序和order by子句的順序完全一致,並且所有列的排序方向都一樣,mysql才能夠使用索引來對結果做排序。如果查詢需要關聯多張表,則只有當order by子句引用的欄位全部為第一個表時,才能使用索引做排序。order by子句需要滿足索引最左字首的要求,如果不滿足,前導列為常量的時候,可以利用索引排序。

Key rental_date(rental_date,inventory_id,customer_id)

select rental_id,staff_id from sakila.rental where rental_date=’2005-05-05’ order by inventory_id,customer_id\G

order by子句不滿足索引最左字首要求,也可以用於查詢排序,因為索引第一列被指定為一個常數。

下列示例不能使用索引做排序查詢

查詢使用了兩個不同的排序方向

..where rental_data=’2005-05-05’ order by inventory_id desc,customer_id asc;

order by使用了一個不在索引中的列

..where rental_date=’2005-05-05’ order by inventory_id,staff_id;

where和order by中的列無法組合成索引的最左字首。

..where rental_date=’2005-05-05’ order by customer_id;

查詢在索引的第一列上時範圍條件,mysql無法使用索引的其餘列

..where rental_date>’2005-05-05’ order by inventory_id,customer_id;

某一列上有多個等於條件,對於排序來說,這也是一種範圍查詢

..where rental_date=’2005-05-05’ and inventory_id in(1,2) order by customer_id;

3.8 壓縮(字首)索引

可以在create table語句中指定pack_keys引數來控制索引壓縮方式。

3.9 冗餘索引和重複索引

刪除,工具common_shema或pt-duplicate-key-checker

3.10 未使用的索引

刪除,工具pt-index-usage

3.11 索引和鎖

InnoDB在訪問行的時候會對其加鎖,索引能夠減少InnoDB訪問的行數,從而減少鎖的數量。如果索引無法過濾掉無效的行,那麼在InnoDB檢索到資料並返回給服務層後,mysql伺服器才能應用where子句。