文章目錄
- 索引
- 引言
- 常見的索引
- 哈希索引
- 自適應哈希索引
- B+樹索引
- 聚集索引
- 非聚集索引
- 使用方法
- 聯合索引
- 最左前綴匹配規則
- 覆蓋索引
- 全文索引
- 使用方法
索引
引言
為什么需要索引?
倘若不使用索引,查找數據時,MySQL必須遍歷整個表。而表越大,查詢的時間則越長,則數據庫的效率也就越低。而索引就類似于書籍的目錄,可以幫助我們快速的定位、檢索到需要的數據行,對提高數據庫的性能有著很大的幫助。
在MySQL中,索引是一種特殊的文件,其中包含著對數據表里所有記錄的引用指針。各類索引有各自的數據結構實現。
索引優缺點
優點:
- 大大加快了數據檢索的速度
- 使用要求低,所有的列類型都可以被索引,也就是可以給任意字段設置索引
缺點:
- 索引需要占用物理空間,建立的索引越多則需要的空間越大。
- 創建和維護索引需要耗費時間,并且時間隨著數據量的增加而增加。
- 當對表中的數據進行增加、刪除、修改的時候,索引也要動態的維護,如果一張表經常需要增刪改,那么有索引的話就降低了數據的更新速度。
適用場景
- 數據量較大,并且經常對這些列進行查詢。
- 該數據庫表的插入、修改操作頻率較低。
常見的索引
因為 MySQL
中索引是在 存儲引擎層 實現的,所以并沒有統一的索引標準,換言之:
- 不同存儲引擎支持的索引類型并不一樣。
- 而即使多個存儲引擎支持同一種類型的索引,其底層的實現也可能不同。
由于 InnoDB存儲引擎
在 MySQL
數據庫中使用最為廣泛,所以下面的討論主要以 InnoDB
為例。
在 InnoDB存儲引擎
中,主要支持以下三種常見的索引:B+樹索引、哈希索引、全文索引。
哈希索引
如不了解哈希可移步哈希 :哈希沖突、負載因子、哈希函數、哈希表、哈希桶
原理:通過除留余數法將鍵值轉換為哈希值,并將數據存儲對應的槽中,如果出現了哈希沖突,則使用鏈地址法進行解決,將數據插入對應槽中的鏈表。
由于哈希是直接通過哈希值來將數據映射到對應位置,所以哈希索引對于等值查詢的效率特別高,但是也正因為這個特性,使得哈希查找在面對范圍查找的時候就毫無用武之地了。
自適應哈希索引
InnoDB存儲引擎
會監控對表上各個索引頁的查詢,如果它觀察到建立哈希索引可以帶來速度提升,則會自行建立哈希索引,這也就是 自適應哈希索引。即會自動根據 訪問頻率和模式 來為 熱點數據 建立哈希索引。
哈希索引是數據庫自身自動創建并使用的,人工無法對其進行干預。
B+樹索引
如不了解B+樹可移步數據結構 | B樹、B+樹、B*樹
比起哈希索引,B+樹索引的優勢主要在于排序查找以及區間查找。
在數據庫中,B+樹索引可以分為聚集索引(主鍵索引)和非聚集索引(輔助索引),它們之間的區別在于葉子節點中存放的是否是一整行的信息(即用戶數據)
PS:葉子節點那一層存儲的是表,而具體的某一個葉子節點才是存儲列。
聚集索引
聚集索引其實就是索引和數據在同一個數據結構中。
由于 InnoDB存儲引擎
中表的數據按照主鍵順序存放,所以聚集索引也就是按照每張表的主鍵來構造出一顆B+樹。由于數據真正的排序方式只能有一種,所以在每張表中只能存在著一個聚集索引。
這顆B+樹的非葉子節點存放的是數據的索引,而葉子節點存放的即為整張表的行記錄數據,所以我們通常也將葉子節點稱為數據頁,并且每個葉子節點之間用雙向鏈表進行連接。
聚集索引對于主鍵的排序查找和范圍查找速度非常快,并且由于葉子節點就是數據,所以只需要查找一次就可以得到結果。
非聚集索引
對于 非聚集索引(輔助索引) 來說,葉子節點并不包含行記錄的全部數據,而是包含了主鍵的值。
也就是說,我們需要在非聚集索引中查找到主鍵,再通過主鍵在聚集索引中查找到具體的值,也就是需要兩次查找。所以非聚集索引其實也就是一個二級索引。
基于以上特性,由于輔助索引的存在并不會影響數據在聚集索引中的存在方式,因此每張表中可以有多個輔助索引。
使用方法
創建主鍵約束(PRIMARY KEY)、唯一約束(UNIQUE)、外鍵約束(FOREIGN KEY)時,會自動創建對應列的索引。
查看索引
SHOW INDEX FROM 表名
創建
CREATE INDEX 索引名 ON 表名(字段名)
或者
ALTER TABLE 表名 ADD {KEY | INDEX} 索引名
刪除
DROP INDEX 索引名 ON 表名
聯合索引
聯合索引即對表上的多個列進行索引:
聯合索引和普通的B+樹不同的地方在于它具有多個鍵值,鍵值按照從左往右的優先級以此對鍵值的大小進行排序,例如:上圖有兩個鍵值,首先會先按照第一個鍵值的大小進行排序,當第一個鍵相同時,再按照第二個鍵的大小進行排序。
因為以上特性,聯合索引具有最左前綴匹配規則,當不滿足規則時則不會使用聯合索引,而是進行全索引掃描。
最左前綴匹配規則
就以上述數據進行舉例,此時以鍵值 (a, b)
構建聯合索引
SELECT * FROM TABLE WHERE a = xxx AND b = xxx 、
SELECT * FROM TABLE WHERE a = xxx
SELECT * FROM TABLE WHERE b = xxx
對于以上幾條查詢語句來說,雖然看起來差不多,但是效率卻大相徑庭。
對于前兩句來說,它們是可以使用聯合索引的,因為無論是按照 a
作為條件,或者是 a
和 b
作為條件。因為前面也說過了,聯合索引的排序是按照從左往右優先的,所以當前兩句都是優先根據 a
進行索引搜索,不會出現問題。
但對于 b=xxx
則無法適用以上性質,因為在聯合索引中,后面的主鍵只有在前面的主鍵相同時才會具有有序性,而單獨適用它的時候顯然數據是無序的,所以這時只能進行全索引掃描。
對于范圍查找也是這么一個道理,假設此時聯合索引的主鍵為(a, b, c)
SELECT * FROM TABLE WHERE a > 3 AND b > 3
SELECT * FROM TABLE WHERE a > 3 AND b > 3 AND c > 3
SELECT * FROM TABLE WHERE a > 3 AND c > 3
同樣按照上面的規則,前兩種查詢都可以適用聯合索引,因為其遵循了從左至右的匹配原則,而第三條因為跳過了 b
,此時的數據是無序的,無法適用索引。
覆蓋索引
覆蓋索引即從輔助索引中就可以得到查詢的記錄,而不需要查詢聚集索引中的記錄。使用覆蓋索引的一個好處就是由于輔助索引中不包含整行的所有記錄,所以它的大小要遠遠小于聚集索引,因此可以減少大量的 I/O
操作。
由于輔助索引中葉子節點存放的數據就是主鍵,所以當我們要查找主鍵,或者通過主鍵來統計數量的時候,就可以使用覆蓋索引來完成。
全文索引
在之前版本中只有 InnoDB
并不支持全文檢索,而在 InnoDB1.2.x
版本之后,InnoDB
也加入了全文檢索的功能。
全文索引即根據部分段落、句、詞從數據庫中查詢除全文的技術,即根據部分查詢詞獲取對應的文檔。
主要依據倒排索引這一數據結構來實現,這一數據結構通常也在搜索引擎中進行使用。
這里就簡要的介紹一下 InnoDB
中的倒排索引。其擁有兩種表現形式:
inverted file index
(倒排文件索引)
表現形式 {單詞, 單詞所在的文檔ID)full inverted index
(全文倒排索引)
表現形式{單詞, (單詞所在文檔ID,在具體文檔的位置)
例如我們存在以下數據:
并將其構建成 inverted file index(倒排文件索引)
的形式:
此時我們就建立起了各個單詞與其對應文檔的一個映射關系。
接著建立 full inverted index(全文倒排索引)
此時在之前的基礎上,我們不僅確定了單詞所在的文章,還確定了其所在文章中的對應位置,雖然比起 inverted file index來
說更加復雜,占據的空間也更多,但是卻能更好的定位數據,并且擴充一些其它的搜索特性。
使用方法
創建全文索引
CREATE FULLTEXT INDEX 索引名 ON 表名(字段名);
查找方法
MATCH(要匹配的列) AGAINST(要查找的內容)
- 自然語言查詢(
Natural Language
),即普通的包含關鍵詞的搜索,例如:
SELECT * FROM (表名) WHERE MATCH(匹配列) AGAINST(查詢內容)
Boolean
,這個模式允許使用IN BOOLEAN MODE修飾符
來進行全文檢索,當使用該修飾符時,查詢字符串的前后字符都會有特殊含義。例如+
和-
分別代表了該單詞必須出現或者一定沒出現。
這句查詢即匹配包含 查詢詞1
并且不包含 查詢詞2
的結果:
SELECT * FROM 表名
WHERE MATCH (要匹配的列) AGAINST ('+查詢詞1 -查詢詞2' IN BOOLEAN MODE);
該模式所有選項如下:
全文查詢的結果依據相關度進行降序排序,相關度計算依據如下:
- 查詢詞是否在文檔中出現過
- 查詢詞在文檔中出現的次數
- 查詢詞在索引列中的數量
- 包含查詢詞的文檔數