數據庫索引

數據庫索引簡介

數據庫索引的定義

數據庫索引是一種數據結構。經過增長額外的寫操做和存儲空間來維護數據庫索引,能夠提升從數據庫中讀取數據的速度。經過索引,不須要搜索數據庫的每一條記錄,就能夠快速地定位到特定的數據。索引能夠建在在表中某一個字段或多個字段之上。總而言之:數據庫索引是一種數據結構mysql

數據庫索引的做用

  1. 用於支持快速地查找到數據sql

    • 若沒有索引,一般須要遍歷全部記錄才能找到相應地數據(O(N));而經過索引,通常只須要O(log(N))次就能夠定位到數據,提升了查找效率
  2. 管理數據庫約束數據庫

    • 索引一般還會被用於管理數據庫約束,例如UNIQUE, EXCLUSION, PRIMARY KEY 和 FOREIGN KEY。當一個索引被定義爲UNIQUE時,數據庫同時建立一個隱式的約束。

Clustered Index & Non-clustered Index

Clustered Index(彙集索引/聚簇索引)

彙集索引是指數據庫錶行中數據的物理順序與鍵值的邏輯(索引)順序相同。一個表只能有一個彙集索引,由於一個表的物理順序只有一種狀況,因此,對應的彙集索引只能有一個。若是某索引不是彙集索引,則表中的行物理順序與索引順序不匹配,與非彙集索引相比,彙集索引有着更快的檢索速度。以下圖,葉節點中直接包含了具體數據。
彙集索引數據結構

Non-clustered Index(非彙集索引/非聚簇索引)

與彙集索引不一樣,非彙集索引的邏輯順序與磁盤上行的物理存儲順序不一樣。磁盤上的數據能夠隨意分佈,而經過非彙集索引,能夠在邏輯上爲數據排序。以下圖,葉節點沒有包含具體的數據,而是包含了一個指向具體數據的指針。
非彙集索引函數

區別

當索引經過二叉樹的形式進行描述時,咱們能夠這樣區分彙集與非彙集索引的區別:彙集索引的葉節點就是最終的數據節點,而非彙集索引的葉節仍然是索引節點,但它有一個指向最終數據的指針。工具

數據庫索引的實現

常見的數據庫索引實現有性能

  1. 平衡樹(B樹)
  2. B+樹
  3. Hashes(哈希)

B樹,B+樹

參考B-tree wikiB+ tree wiki優化

Mysq中的索引

MySQL數據庫支持多種索引類型,如B+ Tree索引,哈希索引,全文索引等等。下面只分析B+ Tree索引。spa

MyISAM索引實現

MyISAM引擎使用B+Tree做爲索引實現,而且全部的索引都是非彙集索引
下圖是主鍵索引:
MyIASAM主鍵索引
若在Col2上創建輔助索引,其依然是一個非彙集索引,與主鍵索引相似:
MyIASAM輔助索引
MyISAM引擎中,使用索引查找數據時,先經過索引獲取到數據的物理地址,而後經過物理地址讀取數據。指針

InnoDB索引實現

InnoDB引擎一樣使用B+Tree做爲索引實現,但與MyISAM不一樣,在InnoDB引擎中,主鍵索引是彙集索引,而輔助索引則是非彙集索引。下圖是主鍵索引:
InnoDDB主鍵索引
若在Col2上創建輔助索引,則是一個非彙集索引,葉節點的值爲數據的主鍵:
InnoDB輔助索引
在InnoDB中,經過主鍵索引,能夠直接獲取到具體的數據;而經過輔助索引,在葉節點獲取到的是數據的主鍵,而後再經過主鍵索引最終獲取到數據。

聯合索引/多列索引

在上面的介紹中,咱們主要是針對一個字段創建索引,而實際上,能夠創建一個基於多個字段的索引。假設某張表中有a,b,c,d四個字段。如今在a,b,c上創建索引(a,b,c)(注意: a,b,c順序不一樣創建的是不一樣的索引)。則索引首先會按a字段排序;在a字段相同的狀況下按照b字段排序;在a,b字段相同的狀況下按照c字段排序,以此類推。。。

最左前綴匹配原則

當創建聯合索引時,該索引的全部最左前綴匹配能夠用於優化查找。以上面創建的(a,b,c)索引爲例,其全部最左前綴匹配爲(a),(a,b),(a,b,c)。即涉及到(a),(a,b),(a,b,c)的查找均可以利用索引(a,b,c),但涉及(a,c)的查找沒法利用索引(a,b,c),由於(a,c)不知足最左前綴匹配原則。

前綴索引

前綴索引就是針對字段的「前特定個字符」創建索引,而非對整個字段的值創建索引。顯然,由於沒有對完整的字段值創建索引,因此這樣創建的索引更小,查詢更快。MySQL的前綴索引能有效減少索引文件的大小,提升索引的速度。可是前綴索引也有它的壞處:MySQL 不能在 ORDER BY 或 GROUP BY 中使用前綴索引,也不能把它們用做覆蓋索引(Covering Index)。
能夠經過下面的預發創建前綴索引:

ALTER TABLE table_name ADD KEY(column_name(prefix_length));

覆蓋索引

覆蓋索引(covering index)指一個查詢語句的執行只須要從輔助索引中就能夠獲得查詢記錄,而不須要查詢彙集索引中的記錄。也能夠稱之爲實現了索引覆蓋。輔助索引不包含一整行的記錄,所以能夠大大減小IO操做。覆蓋索引是mysql dba經常使用的一種SQL優化手段。

Mysql中高性能的索引策略

獨立的列

若是查詢中的列不是獨立的,則MySQL就不會使用索引。「獨立的列」是指索引列不能是表達式的一部分,也不能是函數的參數。所以應該簡化WHERE條件,始終將索引列單獨放在比較符號的一側

SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;(沒法使用actor_id列的索引)
SELECT actor_id FROM sakila.actor WHERE actor_id = 4;(可使用actor_id列的索引)

前綴索引和索引選擇性

有時候須要索引很長的字符列,這會使索引變得大且慢。一般能夠索引開始的部分字符,這樣能夠大大節約索引空間,從而提升索引效率。但這樣也會下降索引的選擇性。索引的選擇性是指,不重複的索引值(也稱爲基數)和數據的記錄總數(#T)的比值,範圍從1/#T到1之間。索引的選擇性越高則查詢效率越高。惟一索引的選擇性是1,這是最好的索引選擇性,性能也是最好的。

通常狀況下某個列的前綴的選擇性也是足夠高的,足以知足查詢性能。對於BLOB,TEXT或很長的VARCHAR類型的列,必須使用前綴索引,由於MySQL不容許索引這些列的完整長度。一般狀況,咱們應該儘可能使前綴的「基數」接近於完整列的「基數」。

前綴索引的缺點 : MySQL沒法使用前綴索引作ORDER BY和GROUP BY,也沒法使用前綴索引作覆蓋掃描。


多列索引

在多個列上創建獨立的單列索引大部分狀況下並不能提升MySQL的查詢性能。此時應該考慮創建多列索引。


選擇合適的索引列順序(針對B-Tree索引)

當不須要考慮排序和分組時,一般將選擇性最高的列放到索引最前列。
有時可能須要根據那些運行頻率最高的查詢來調整索引列的順序。


覆蓋索引

若是一個索引包含(或者說是覆蓋)全部須要查詢的字段的值,咱們就稱爲「覆蓋索引」,使用覆蓋索引可以極大地提升性能。


使用索引來作排序

MySQL可使用同一個索引既知足排序,又用於查找行。所以,若是可能,涉及索引時應該儘量地同時知足這兩種任務。只有當索引的列順序和ORDER BY子句的順序徹底一致,而且索引列的排序方向(倒序或正序)都同樣時,MySQL才能使用索引來對結果排序。若是查詢須要關聯多張表,則只有當ORDER BY子句引用的字段所有爲第一個表時,才能使用索引作排序。ORDER BY子句和查找型查詢的限制是同樣的:須要知足索引的最左前綴需求;不然,MySQL都須要執行排序操做,而沒法利用索引排序。


冗餘和重複索引

重複索引是指在相同的列上按照相同的順序建立相同類型的索引,應該避免這樣建立的重複索引,發現後也應該當即移除。MySQL容許在相同列上建立多個索引。MySQL須要單獨維護重複的索引,而且優化器在優化查詢的時候也須要逐個地進行考慮,這會影響性能。

冗餘索引和重複索引又一些不一樣。若是建立了索引(A,B),再建立索引(A)就是冗餘索引,由於這只是前一個索引的前綴索引。大多數狀況下,都不須要冗餘索引,應該儘量擴展已有的索引而不是建立新索引。但也有時候出於性能方面的考慮須要冗餘索引,由於擴展已有的索引會致使其變得太大,從而影響其餘使用該索引的查詢的性能。


未使用的索引

若一個索引再也不被使用,則應該考慮刪除。能夠經過一些工具找到未使用的索引,如Percona Toolkit中的pt-index-usage

相關文章
相關標籤/搜索