數據庫索引是一種數據結構。經過增長額外的寫操做和存儲空間來維護數據庫索引,能夠提升從數據庫中讀取數據的速度。經過索引,不須要搜索數據庫的每一條記錄,就能夠快速地定位到特定的數據。索引能夠建在在表中某一個字段或多個字段之上。總而言之:數據庫索引是一種數據結構mysql
用於支持快速地查找到數據sql
管理數據庫約束數據庫
彙集索引是指數據庫錶行中數據的物理順序與鍵值的邏輯(索引)順序相同。一個表只能有一個彙集索引,由於一個表的物理順序只有一種狀況,因此,對應的彙集索引只能有一個。若是某索引不是彙集索引,則表中的行物理順序與索引順序不匹配,與非彙集索引相比,彙集索引有着更快的檢索速度。以下圖,葉節點中直接包含了具體數據。
數據結構
與彙集索引不一樣,非彙集索引的邏輯順序與磁盤上行的物理存儲順序不一樣。磁盤上的數據能夠隨意分佈,而經過非彙集索引,能夠在邏輯上爲數據排序。以下圖,葉節點沒有包含具體的數據,而是包含了一個指向具體數據的指針。
函數
當索引經過二叉樹的形式進行描述時,咱們能夠這樣區分彙集與非彙集索引的區別:彙集索引的葉節點就是最終的數據節點,而非彙集索引的葉節仍然是索引節點,但它有一個指向最終數據的指針。工具
常見的數據庫索引實現有性能
MySQL數據庫支持多種索引類型,如B+ Tree索引,哈希索引,全文索引等等。下面只分析B+ Tree索引。spa
MyISAM引擎使用B+Tree做爲索引實現,而且全部的索引都是非彙集索引。
下圖是主鍵索引:
若在Col2上創建輔助索引,其依然是一個非彙集索引,與主鍵索引相似:
MyISAM引擎中,使用索引查找數據時,先經過索引獲取到數據的物理地址,而後經過物理地址讀取數據。指針
InnoDB引擎一樣使用B+Tree做爲索引實現,但與MyISAM不一樣,在InnoDB引擎中,主鍵索引是彙集索引,而輔助索引則是非彙集索引。下圖是主鍵索引:
若在Col2上創建輔助索引,則是一個非彙集索引,葉節點的值爲數據的主鍵:
在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就不會使用索引。「獨立的列」是指索引列不能是表達式的一部分,也不能是函數的參數。所以應該簡化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的查詢性能。此時應該考慮創建多列索引。
當不須要考慮排序和分組時,一般將選擇性最高的列放到索引最前列。
有時可能須要根據那些運行頻率最高的查詢來調整索引列的順序。
若是一個索引包含(或者說是覆蓋)全部須要查詢的字段的值,咱們就稱爲「覆蓋索引」,使用覆蓋索引可以極大地提升性能。
MySQL可使用同一個索引既知足排序,又用於查找行。所以,若是可能,涉及索引時應該儘量地同時知足這兩種任務。只有當索引的列順序和ORDER BY子句的順序徹底一致,而且索引列的排序方向(倒序或正序)都同樣時,MySQL才能使用索引來對結果排序。若是查詢須要關聯多張表,則只有當ORDER BY子句引用的字段所有爲第一個表時,才能使用索引作排序。ORDER BY子句和查找型查詢的限制是同樣的:須要知足索引的最左前綴需求;不然,MySQL都須要執行排序操做,而沒法利用索引排序。
重複索引是指在相同的列上按照相同的順序建立相同類型的索引,應該避免這樣建立的重複索引,發現後也應該當即移除。MySQL容許在相同列上建立多個索引。MySQL須要單獨維護重複的索引,而且優化器在優化查詢的時候也須要逐個地進行考慮,這會影響性能。
冗餘索引和重複索引又一些不一樣。若是建立了索引(A,B),再建立索引(A)就是冗餘索引,由於這只是前一個索引的前綴索引。大多數狀況下,都不須要冗餘索引,應該儘量擴展已有的索引而不是建立新索引。但也有時候出於性能方面的考慮須要冗餘索引,由於擴展已有的索引會致使其變得太大,從而影響其餘使用該索引的查詢的性能。
若一個索引再也不被使用,則應該考慮刪除。能夠經過一些工具找到未使用的索引,如Percona Toolkit中的pt-index-usage