上一章講了數據庫基本上都用 B+ 樹來存儲索引的緣由:適合磁盤存儲,可以充分利用多叉平衡樹的特性,磁盤預讀,而且很好的支持等值,範圍,順序掃描等。這篇主要介紹 MySQL 兩種經常使用引擎,MyISAM 和 InnoDB 的索引組織方式,瞭解這些存儲方式,對數據庫優化頗有幫助。mysql
彙集索引:也稱 Clustered Index。是指關係表記錄的物理順序與索引的邏輯順序相同。因爲一張表只能按照一種物理順序存放,一張表最多也只能存在一個彙集索引。與非彙集索引相比,彙集索引有着更快的檢索速度。sql
MySQL 裏只有 INNODB 表支持彙集索引,INNODB 表數據自己就是彙集索引,也就是常說 IOT,索引組織表。非葉子節點按照主鍵順序存放,葉子節點存放主鍵以及對應的行記錄。因此對 INNODB 表進行全表順序掃描會很是快。數據庫
非彙集索引:也叫 Secondary Index。指的是非葉子節點按照索引的鍵值順序存放,葉子節點存放索引鍵值以及對應的主鍵鍵值。MySQL 裏除了 INNODB 表主鍵外,其餘的都是二級索引。MYISAM,memory 等引擎的表索引都是非彙集索引。簡單點說,就是索引與行數據分開存儲。一張表能夠有多個二級索引。 優化
MYISAM 表是典型的數據與索引分離存儲,主鍵和二級索引沒有本質區別。好比在 MYISAM 表裏主鍵、惟一索引是同樣的,沒有本質區別。spa
假設表 t1 爲 MYISAM 引擎,列爲 ID,姓名,性別,年齡,手機號碼。其中 ID 爲主鍵,年齡爲二級索引。記錄以下:設計
那對應的兩個 B+ 樹索引以下圖所示,3d
上圖是一個 3 階的 B+ 樹,非葉子節點按照主鍵的值排序存儲,葉子節點一樣按照主鍵的值排序存儲,而且包含指向磁盤上的物理數據行指針。 指針
上圖年齡字段索引樹一樣是一個 3 階的 B+ 樹,非葉子節點按照年齡字段的值順序存儲,葉子節點保存年齡字段的值以及指向磁盤上的物理數據行指針。code
從上面兩張圖能夠看出,MYISAM 表的索引存儲方式最大的缺點沒有按照物理數據行順序存儲,這樣不管對主鍵的檢索仍是對二級索引的檢索都須要進行二次排序。 blog
舉個簡單例子演示下,
如下 SQL 1 默認沒有排序,亂序輸出;須要按照 ID 順序輸出,就得用 SQL 2,顯式加 ORDER BY 。
mysql # SQL 1 mysql> select * from t1; +-------+----------+--------+------+--------------+ | id | username | gender | age | phone_number | +-------+----------+--------+------+--------------+ | 10001 | 小花 | 女 | 18 | 18501877098 | | 10005 | 小李 | 女 | 21 | 15827654555 | | 10006 | 小白 | 男 | 38 | 19929933000 | | 10009 | 小何 | 男 | 35 | 19012378676 | | 10002 | 小王 | 男 | 20 | 17760500293 | | 10003 | 小趙 | 女 | 29 | 13581386000 | | 10004 | 小青 | 女 | 25 | 13456712000 | | 10007 | 小米 | 男 | 23 | 19800092354 | | 10008 | 小徐 | 女 | 22 | 18953209331 | +-------+----------+--------+------+--------------+ 9 rows in set (0.00 sec) # SQL 2 mysql> select * from t1 order by id; +-------+----------+--------+------+--------------+ | id | username | gender | age | phone_number | +-------+----------+--------+------+--------------+ | 10001 | 小花 | 女 | 18 | 18501877098 | | 10002 | 小王 | 男 | 20 | 17760500293 | | 10003 | 小趙 | 女 | 29 | 13581386000 | | 10004 | 小青 | 女 | 25 | 13456712000 | | 10005 | 小李 | 女 | 21 | 15827654555 | | 10006 | 小白 | 男 | 38 | 19929933000 | | 10007 | 小米 | 男 | 23 | 19800092354 | | 10008 | 小徐 | 女 | 22 | 18953209331 | | 10009 | 小何 | 男 | 35 | 19012378676 | +-------+----------+--------+------+--------------+ 9 rows in set (0.00 sec)
接下來看看 INNODB 的主鍵索引和二級索引的組成方式。
INNODB 表自己是索引組織表,也就是說索引就是數據。下圖表T1的數據行以聚簇索引的方式展現,非葉子節點保存了主鍵的值,葉子節點保存了主鍵的值以及對應的數據行,而且每一個頁有分別指向先後兩頁的指針。
INNODB 表不一樣於 MYISAM,INNODB 表有本身的數據頁管理,默認 16KB。MYISAM 表數據的管理依賴文件系統,好比文件系統通常默認 4KB,MYISAM 的塊大小也是 4KB,MYISAM 表的沒有本身的一套崩潰恢復機制,所有依賴於文件系統。
INNODB 表這樣設計的優勢有兩個:
mysql mysql> select * from t1; +-------+----------+--------+------+--------------+ | id | username | gender | age | phone_number | +-------+----------+--------+------+--------------+ | 10001 | 小花 | 女 | 18 | 18501877098 | | 10002 | 小王 | 男 | 20 | 17760500293 | | 10003 | 小趙 | 女 | 29 | 13581386000 | | 10004 | 小青 | 女 | 25 | 13456712000 | | 10005 | 小李 | 女 | 21 | 15827654555 | | 10006 | 小白 | 男 | 38 | 19929933000 | | 10007 | 小米 | 男 | 23 | 19800092354 | | 10008 | 小徐 | 女 | 22 | 18953209331 | | 10009 | 小何 | 男 | 35 | 19012378676 | +-------+----------+--------+------+--------------+ 9 rows in set (0.00 sec)
再來看下 INNODB 表的二級索引,以下圖所示:
INNODB 二級索引的非葉子節點保存索引的字段值,上圖索引爲表 t1 的字段 age。葉子節點含有索引字段值和對應的主鍵值。
這樣作的優勢是當出現數據行移動或者數據頁分裂時,避免二級索引沒必要要的維護工做。當數據須要更新的時候,二級索引不須要重建,只須要修改聚簇索引便可。
可是也有缺點:
舉個例子:
以下 SQL 語句,檢索年齡爲 23 的行記錄:
mysql select * from t1 where age = 23;
會拆分紅如下兩個 SQL 語句:
先經過索引字段 age 找到對應的主鍵值:10005.
mysql select id from t1 where age=23;
再去聚簇索引上根據主鍵 ID = 10005 檢索到須要的數據行,若是表第一次讀取,就須要回表。
mysql select * from t1 where id = 10005;
不過 MySQL 對這塊作了很好的優化,提早作了數據預熱(數據預熱,這裏就不講了,能夠參考 MySQL 手冊,手冊上介紹的很詳細)。
本篇內容介紹到此,簡單回顧下本篇內容。本篇主要介紹 MySQL 常見的兩種引擎 MYISAM 和 INNODB 的索引組織方式以及各自的優缺點。有問題歡迎批評指正,下一篇我來介紹 MySQL 如何很好的對主鍵進行設計。
關於 MySQL 的技術內容,大家還有什麼想知道的嗎?趕忙留言告訴小編吧!