MySQL數據庫中的索引(二)——索引的使用,最左前綴原則


上文中,我們了解了MySQL不同引擎下索引的實現原理,在本文我們將繼續探討一下索引的使用以及優化。

創建索引可以大大提高系統的性能。

第一,通過創建唯一性索引,可以保證數據庫表中每一行數據的唯一性。

第二,可以大大加快數據的檢索速度,這也是創建索引的最主要的原因。

第三,可以加速表和表之間的連接,特別是在實現數據的參考完整性方面特別有意義。

第四,在使用分組和排序子句進行數據檢索時,同樣可以顯著減少查詢中分組和排序的時間。

第五,通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的性能。 

 

也許會有人要問:增加索引有如此多的優點,為什么不對表中的每一個列創建一個索引呢?因為,增加索引也有許多不利的方面。

第一,創建索引和維護索引要耗費時間,這種時間隨着數據量的增加而增加。

第二,索引需要占物理空間,除了數據表占數據空間之外,每一個索引還要占一定的物理空間,如果要建立聚簇索引,那么需要的空間就會更大。

第三,當對表中的數據進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了數據的維護速度。

 

索引是建立在數據庫表中的某些列的上面。在創建索引的時候,應該考慮在哪些列上可以創建索引,在哪些列上不能創建索引。一般來說,應該在這些列上創建索引:在經常需要搜索的列上,可以加快搜索的速度;在作為主鍵的列上,強制該列的唯一性和組織表中數據的排列結構;在經常用在連接的列上,這些列主要是一些外鍵,可以加快連接的速度;在經常需要根據范圍進行搜索的列上創建索引,因為索引已經排序,其指定的范圍是連續的;在經常需要排序的列上創建索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;在經常使用在WHERE子句中的列上面創建索引,加快條件的判斷速度。

 

同樣,對於有些列不應該創建索引。一般來說,不應該創建索引的的這些列具有下列特點:

第一,對於那些在查詢中很少使用或者參考的列不應該創建索引。這是因為,既然這些列很少使用到,因此有索引或者無索引,並不能提高查詢速度。相反,由於增加了索引,反而降低了系統的維護速度和增大了空間需求。

第二,對於那些只有很少數據值的列也不應該增加索引。這是因為,由於這些列的取值很少,例如人事表的性別列,在查詢的結果中,結果集的數據行占了表中數據行的很大比例,即需要在表中搜索的數據行的比例很大。增加索引,並不能明顯加快檢索速度。

第三,對於那些定義為text, image和bit數據類型的列不應該增加索引。這是因為,這些列的數據量要么相當大,要么取值很少。

第四,當修改性能遠遠大於檢索性能時,不應該創建索引。這是因為,修改性能和檢索性能是互相矛盾的。當增加索引時,會提高檢索性能,但是會降低修改性能。當減少索引時,會提高修改性能,降低檢索性能。因此,當修改性能遠遠大於檢索性能時,不應該創建索引。


 

 

我們先來看一下索引的分類,索引大致可按如下分類:

從數據結構角度

1、B+樹索引(O(log(n))):關於B+樹索引,可以參考 MySQL索引背后的數據結構及算法原理

2、hash索引:

a. 僅僅能滿足"=","IN"和"<=>"查詢,不能使用范圍查詢
b. 其檢索效率非常高,索引的檢索可以一次定位,不像B-Tree 索引需要從根節點到枝節點,最后才能訪問到頁節點這樣多次的IO訪問,所以 Hash 索引的查詢效率要遠高於 B-Tree 索引
c. 只有Memory存儲引擎顯示支持hash索引

從物理存儲角度

1、聚集索引(clustered index)

2、非聚集索引(non-clustered index)

從邏輯角度

1、普通索引或者單列索引

2、唯一索引

3、主鍵索引:主鍵索引是一種特殊的唯一索引,不允許有空值

4、多列索引(復合索引):復合索引指多個字段上創建的索引,只有在查詢條件中使用了創建索引時的第一個字段,索引才會被使用。使用復合索引時遵循最左前綴集合

5、全文索引

 

在上文中,我們已經了解了數據結構及物理存儲角度,今天我們主要從邏輯角度來看看索引:

1、普通索引:這是最基本的索引類型,而且它沒有唯一性之類的限制。普通索引可以通過以下幾種方式創建: 
創建索引,例如CREATE INDEX <索引的名字> ON tablename (列的列表); 
修改表,例如ALTER TABLE tablename ADD INDEX [索引的名字] (列的列表); 
創建表的時候指定索引,例如CREATE TABLE tablename ( [...], INDEX [索引的名字] (列的列表) ); 

 

2、唯一索引:這種索引和前面的“普通索引”基本相同,但有一個區別:索引列的所有值都只能出現一次,即必須唯一。唯一性索引可以用以下幾種方式創建: 
創建索引,例如CREATE UNIQUE INDEX <索引的名字> ON tablename (列的列表); 
修改表,例如ALTER TABLE tablename ADD UNIQUE [索引的名字] (列的列表); 
創建表的時候指定索引,例如CREATE TABLE tablename ( [...], UNIQUE [索引的名字] (列的列表) ); 

 

3、主鍵索引

主鍵是一種唯一性索引,但它必須指定為“PRIMARY KEY”。如果你曾經用過AUTO_INCREMENT類型的列,你可能已經熟悉主鍵之類的概念了。主鍵一般在創建表的時候指定,例如“CREATE TABLE tablename ( [...], PRIMARY KEY (列的列表) ); ”。但是,我們也可以通過修改表的方式加入主鍵,例如“ALTER TABLE tablename ADD PRIMARY KEY (列的列表); ”。每個表只能有一個主鍵。

 

4、復合索引(組合索引、多列索引)

為了形象地對比單列索引和組合索引,為表添加多個字段:

CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, city VARCHAR(50) NOT NULL, age INT NOT NULL );

為了進一步榨取MySQL的效率,就要考慮建立組合索引。就是將 name, city, age建到一個索引里:

ALTER TABLE mytable ADD INDEX name_city_age (name(10),city,age);

建表時,usernname長度為 16,這里用 10。這是因為一般情況下名字的長度不會超過10,這樣會加速索引查詢速度,還會減少索引文件的大小,提高INSERT的更新速度。

如果分別在 usernname,city,age上建立單列索引,讓該表有3個單列索引,查詢時和上述的組合索引效率也會大不一樣,遠遠低於我們的組合索引。雖然此時有了三個索引,但MySQL只能用到其中的那個它認為似乎是最有效率的單列索引。

建立這樣的組合索引,其實是相當於分別建立了下面三組組合MySQL數據庫索引:

usernname,city,age  usernname,city  usernname 為什么沒有 city,age這樣的組合索引呢?這是因為MySQL組合索引“最左前綴”的結果。簡單的理解就是只從最左面的開始組合。並不是只要包含這三列的查詢都會用到該組合索引,下面的幾個SQL就會用到這個組合MySQL數據庫索引:

SELECT * FROM mytable WHREE username="admin" AND city="鄭州"

SELECT * FROM mytable WHREE username="admin"

而下面幾個則不會用到:

SELECT * FROM mytable WHREE age=20 AND city="鄭州" SELECT * FROM mytable WHREE city="鄭州"

關於最左前綴的問題,我們會在后面討論到

 

5、全文索引

MySQL從3.23.23版開始支持全文索引和全文檢索。在MySQL中,全文索引的索引類型為FULLTEXT。全文索引可以在VARCHAR或者 TEXT類型的列上創建。它可以通過CREATE TABLE命令創建,也可以通過ALTER TABLE或CREATE INDEX命令創建。對於大規模的數據集,通過ALTER TABLE(或者CREATE INDEX)命令創建全文索引要比把記錄插入帶有全文索引的空表更快。本文下面的討論不再涉及全文索引,要了解更多信息,請參見mysql全文索引


最左前綴原則

mysql建立多列索引(聯合索引)有最左前綴的原則,即最左優先,如:

如果有一個2列的索引(col1,col2),則已經對(col1)、(col1,col2)上建立了索引;
如果有一個3列索引(col1,col2,col3),則已經對(col1)、(col1,col2)、(col1,col2,col3)上建立了索引;

1、b+樹的數據項是復合的數據結構,比如(name,age,sex)的時候,b+樹是按照從左到右的順序來建立搜索樹的,比如當(張三,20,F)這樣的數據來檢索的時候,b+樹會優先比較name來確定下一步的所搜方向,如果name相同再依次比較age和sex,最后得到檢索的數據;但當(20,F)這樣的沒有name的數據來的時候,b+樹就不知道第一步該查哪個節點,因為建立搜索樹的時候name就是第一個比較因子,必須要先根據name來搜索才能知道下一步去哪里查詢。

2、比如當(張三,F)這樣的數據來檢索時,b+樹可以用name來指定搜索方向,但下一個字段age的缺失,所以只能把名字等於張三的數據都找到,然后再匹配性別是F的數據了, 這個是非常重要的性質,即索引的最左匹配特性。(這種情況無法用到聯合索引)

關於最左前綴的使用,有下面兩條說明:

  • 最左前綴匹配原則,非常重要的原則,mysql會一直向右匹配直到遇到范圍查詢(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調整。
  • =和in可以亂序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優化器會幫你優化成索引可以識別的形式

關於最左前綴的例子,請參考:https://www.kancloud.cn/kancloud/theory-of-mysql-index/41857


什么時候索引會失效

  1. 如果條件中有or,即使其中有條件帶索引也不會使用(這也是為什么盡量少用or的原因)。注意:要想使用or,又想讓索引生效,只能將or條件中的每個列都加上索引
  2. 對於多列索引,不是使用的第一部分,則不會使用索引(即不符合最左前綴原則)
  3. like查詢是以%開頭
  4. 如果列類型是字符串,那一定要在條件中將數據使用引號引用起來,否則不使用索引
  5. 如果mysql估計使用全表掃描要比使用索引快,則不使用索引

此外,查看索引的使用情況

show status like ‘Handler_read%’;
大家可以注意:
handler_read_key:這個值越高越好,越高表示使用索引查詢到的次數
handler_read_rnd_next:這個值越高,說明查詢低效

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM