-
索引的概念
MySQL 官方對索引的定義為:索引(Index)是幫助 MySQL 高效獲取數(shù)據(jù)的數(shù)據(jù)結構??梢缘玫剿饕谋举|:索引是數(shù)據(jù)結構??梢院唵卫斫鉃榕藕眯虻目焖俨檎覕?shù)據(jù)結構。
在數(shù)據(jù)之外,數(shù)據(jù)庫系統(tǒng)還維護著滿足特定查找算法的數(shù)據(jù)結構,這些數(shù)據(jù)結構以某種方式引用(指向)數(shù)據(jù),這樣就可以在這些數(shù)據(jù)結構上實現(xiàn)高級查找算法。這種數(shù)據(jù)結構,就是索引。下圖就是一種可能的索引方式示例:
image.png
左邊是數(shù)據(jù)表,一共有兩列七條記錄,最左邊的是數(shù)據(jù)記錄的物理地址。為了加快 Col2 的查找,可以維護一個右邊所示的二叉查找樹,每個節(jié)點分別包含索引鍵值和一個指向對應數(shù)據(jù)記錄物理地址的指 針,這樣就可以運用二叉查找在一定的復雜度內獲取到相應數(shù)據(jù),從而快速的檢索出符合條件的記錄。
一般來說索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲的磁盤上。
優(yōu)點:
1 提高數(shù)據(jù)檢索的效率,降低數(shù)據(jù)庫的IO成本。
2 通過索引列對數(shù)據(jù)進行排序,降低數(shù)據(jù)排序的成本,降低了CPU的消耗。
劣勢:
1 雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對表進行INSERT、UPDATE和DELETE。因為 更新表時,MySQL不僅要保存數(shù)據(jù),還要保存一下索引文件每次更新添加了索引列的字段,都會調整因為 更新所帶來的鍵值變化后的索引信息。
2 實際上索引也是一張表,該表保存了主鍵與索引字段,并指向實體表的記錄,所以索引列也是要占用空間
的。
2.Mysql 的索引
2.1Btree 索引

一顆 b 樹,淺藍色的塊我們稱之為一個磁盤塊,可以看到每個磁盤塊包含幾個數(shù)據(jù)項(深藍色所示)和指針(黃色所示),如磁盤塊 1 包含數(shù)據(jù)項 17 和 35,包含指針 P1、P2、P3, P1 表示小于 17 的磁盤塊,P2 表示在 17 和 35 之間的磁盤塊,P3 表示大于 35 的磁盤塊。真實的數(shù)據(jù)存在于葉子節(jié)點即 3、5、9、10、13、15、28、29、36、60、75、79、90、99。 非葉子節(jié)點只不存儲真實的數(shù)據(jù),只存儲指引搜索方向的數(shù)據(jù)項,如 17、35 并不真實存在于數(shù)據(jù)表中。
查找過程:
如果要查找數(shù)據(jù)項 29,那么首先會把磁盤塊 1 由磁盤加載到內存,此時發(fā)生一次 IO,在內存中用二分查找確定 29 在 17 和 35 之間,鎖定磁盤塊 1 的 P2 指針,內存時間因為非常短(相比磁盤的 IO)可以忽略不計,通過磁盤塊 1 的 P2 指針的磁盤地址把磁盤塊 3 由磁盤加載到內存,發(fā)生第二次 IO,29 在 26 和 30 之間,鎖定磁盤塊 3 的 P2 指 針,通過指針加載磁盤塊 8 到內存,發(fā)生第三次 IO,同時內存中做二分查找找到 29,結束查詢,總計三次 IO。
真實的情況是,3 層的 b+樹可以表示上百萬的數(shù)據(jù),如果上百萬的數(shù)據(jù)查找只需要三次 IO,性能提高將是巨大的, 如果沒有索引,每個數(shù)據(jù)項都要發(fā)生一次 IO,那么總共需要百萬次的 IO,顯然成本非常非常高。
2.2B+tree 索引

B+Tree 與 B-Tree 的區(qū)別
1)B-樹的關鍵字和記錄是放在一起的,葉子節(jié)點可以看作外部節(jié)點,不包含任何信息;B+樹的非葉子節(jié)點中只有關鍵字和指向下一個節(jié)點的索引,記錄只放在葉子節(jié)點中。
2)在 B-樹中,越靠近根節(jié)點的記錄查找時間越快,只要找到關鍵字即可確定記錄的存在;而 B+樹中每個記錄 的查找時間基本是一樣的,都需要從根節(jié)點走到葉子節(jié)點,而且在葉子節(jié)點中還要再比較關鍵字。從這個角度看 B樹的性能好像要比 B+樹好,而在實際應用中卻是 B+樹的性能要好些。因為 B+樹的非葉子節(jié)點不存放實際的數(shù)據(jù), 這樣每個節(jié)點可容納的元素個數(shù)比 B-樹多,樹高比 B-樹小,這樣帶來的好處是減少磁盤訪問次數(shù)。盡管 B+樹找到 一個記錄所需的比較次數(shù)要比 B-樹多,但是一次磁盤訪問的時間相當于成百上千次內存比較的時間,因此實際中 B+樹的性能可能還會好些,而且 B+樹的葉子節(jié)點使用指針連接在一起,方便順序遍歷(例如查看一個目錄下的所有 文件,一個表中的所有記錄等),這也是很多數(shù)據(jù)庫和文件系統(tǒng)使用 B+樹的緣故。
2.3 聚簇索引和非聚簇索引
聚簇索引并不是一種單獨的索引類型,而是一種數(shù)據(jù)存儲方式。術語‘聚簇’表示數(shù)據(jù)行和相鄰的鍵值聚簇的存儲在一起。如下圖,左側的索引就是聚簇索引,因為數(shù)據(jù)行在磁盤的排列和索引排序保持一致。

聚簇索引的好處:
按照聚簇索引排列順序,查詢顯示一定范圍數(shù)據(jù)的時候,由于數(shù)據(jù)都是緊密相連,數(shù)據(jù)庫不不用從多 個數(shù)據(jù)塊中提取數(shù)據(jù),所以節(jié)省了大量的 io 操作。
聚簇索引的限制:
對于 mysql 數(shù)據(jù)庫目前只有 innodb 數(shù)據(jù)引擎支持聚簇索引,而 Myisam 并不支持聚簇索引。 由于數(shù)據(jù)物理存儲排序方式只能有一種,所以每個 Mysql 的表只能有一個聚簇索引。一般情況下就是該表的主鍵。 為了充分利用聚簇索引的聚簇的特性,所以 innodb 表的主鍵列盡量選用有序的順序 id,而不建議用 無序的 id,比如 uuid 這種。
非聚簇索引(二級索引):
除了主鍵以外,用戶創(chuàng)建的其他索引,也是B+tree結構,鍵值就是建立了索引的那個字段,葉子節(jié)點的值(指針指向的)其實就是主鍵,一般查詢會先根據(jù)二級索引(建立了二級索引的字段)查找對應的主鍵,再根據(jù)主鍵查找數(shù)據(jù)表的B+tree,找到對應的記錄行數(shù)據(jù)。
3.Mysql 索引分類
3.1 單值索引
概念:即一個索引只包含單個列,一個表可以有多個單列索引
創(chuàng)建表:
CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name
VARCHAR(200),
PRIMARYKEY(id),
KEY(customer_name)
);
單獨建單值索引:
CREATE INDEXidx_customer_name ON customer(customer_name);
3.2 唯一索引
概念:索引列的值必須唯一,但允許有空值
創(chuàng)建表:
CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name
VARCHAR(200),
PRIMARYKEY(id),
KEY(customer_name),
UNIQUE(customer_no)
);
單獨建唯一索引:
CREATE UNIQUE INDEX idx_customer_no ON customer(customer_no)
3.3 主鍵索引
概念:設定為主鍵后數(shù)據(jù)庫會自動建立索引,innodb為聚簇索引
創(chuàng)建表:
CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name
VARCHAR(200),
PRIMARYKEY(id)
);
單獨建主鍵索引:
ALTERTABLEcustomeraddPRIMARYKEYcustomer(customer_no);
刪除建主鍵索引:
ALTERTABLEcustomerdropPRIMARYKEY;
3.4 復合索引
概念:即一個索引包含多個列
創(chuàng)建表:
CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name
VARCHAR(200),
PRIMARYKEY(id),
KEY(customer_name),
UNIQUE(customer_name),
KEY(customer_no,customer_name)
);
單獨建索引:
CREATE INDEX idx_no_name ON customer(customer_no,customer_name);
3.5 基本語法
創(chuàng)建: CREATE [UNIQUE] INDEX[indexName] ON table_name(column))
刪除: DROP INDEX[indexName] ON mytable;
查看: SHOW INDEX FROM table_name\G
- 索引的創(chuàng)建時機
4.1 適合創(chuàng)建索引的情況
主鍵自動建立唯一索引;
頻繁作為查詢條件的字段應該創(chuàng)建索引
查詢中與其它表關聯(lián)的字段,外鍵關系建立索引
單鍵/組合索引的選擇問題, 組合索引性價比更高
查詢中排序的字段,排序字段若通過索引去訪問將大大提高排序速度
查詢中統(tǒng)計或者分組字段
4.2 不適合創(chuàng)建索引的情況
表記錄太少
經常增刪改的表或者字段
Where 條件里用不到的字段不創(chuàng)建索引
過濾性不好的不適合建索引
