1,BTREE是多叉樹,多路徑搜索樹。有N棵子樹的節點它包含N-1個關鍵字,例如,有3個子樹的非葉子節點,那么就有2個關鍵字,每個關鍵字不保存數據,只用來存儲索引(在索引存儲數據時,將索引指向關鍵字的值也存儲進來。最終實現key = &get; value結構)。所有的數據最終都要落在葉子節點,所有的葉子節點包括關鍵字信息以及指向這些關鍵字的指針,而且葉子節點是根據關鍵字大小、順序鏈接的。所有的葉子節點都必須有個鏈表指針把數據串起來。所以,所有非葉子節點可以看成索引部分,包括子樹中最大值或最小值關鍵字等信息。在btree索引下,獲取數據時只需要從索引樹的最小節點,一直不斷的向右進行遍歷就可以快速的得到想要的數據(這種遍歷有指針把數據串起來),不需要回溯到根節點, 這樣就可以理解為什么innodb的主鍵索引不能用離散的數據。
下圖為2層btree結構:
btree數據量分布情況:
2,哈希索引建立在哈希表的基礎上,它對每個值采用精確查找。每一行都需要先計算哈希碼,比較好的哈希算法算出比較低的重復的度,這樣效率相對高一些。如果算出來的值是一樣的,那么它需要再進行判斷哪個值才是想要的值,所以說在表里面采用哈希索引,但是重復度又比較高,那么哈希索引效率就比較低,可以使用select crc32('xxx');計算出哈希碼,利用這個哈希值指向具體的數據位置。
HASH索引PK BTREE索引:大量不同數據等值精確查詢,HASH索引效率通常比BTREE高;HASH索引不支持聯合索引的最左匹配規則(where a =? and b=? ,index(a,b,c)這樣無法同時使用a,b,c,相當於是范圍查詢);HASH索引不支持排序;HASH索引不支持模糊查找;
下圖為哈希索引:
3,聚集索引,其實就是索引的組織方式,整個表存儲的邏輯順序根聚集索引的順序是一致的,也就是說聚集索引決定了整個表的物理的存儲的邏輯順序。mysql一個表只支持一個聚集索引。在innodb里面聚集索引就是整個表,表就是聚集索引,因為innodb的聚集索引后面是整行數據(如果主鍵由多列組成,btree優先按第一列順序存儲),在聚集索引btree里面每個葉子節點最終存儲每行數據,這就是為什么在innodb里面沒有任何條件count (*),它會優先選擇普通索引來完成掃描,而不是采用主鍵索引,因為如果掃聚集索引,掃描的數據量更大,產生的IO更大,如果掃描普通輔助索引,那么它的數據結構通常來講比主鍵索引小。另外,為了實現mvcc聚集索引還存儲了rollback point和事物ID。
innodb的普通索引葉子節點里面存儲着主鍵索引的鍵值。聚集索引決定了物理表的存儲順序,如果聚集索引頻繁修改,可能會導致修改存儲的順序,那么這個行數據會產生位移,產生數據離散IO。如果新增的數據太過離散,也會導致聚集索引存儲的位置相應的離散,也會導致隨機IO.
innodb的index extentions特性:mysql5.6.9版本以后,在innodb普通索引里面存儲着主鍵鍵值,目的是根據普通索引掃描時能根據普通索引鍵值找到主鍵並找到對應的數據。如下圖:#官方文檔,https://dev.mysql.com/doc/refman/5.6/en/index-extensions.html
create table innodb_table_monitor
(id int)engine=innodb;#隨便字段只要是innodb表,會把以下信息打印到日志,創建后10s左右生效。
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESpaces WHERE NAME like '%t1%'; #5.7查看視圖才可以
mysql> show create table zhangshuo\G *************************** 1. row *************************** Table: zhangshuo Create Table: CREATE TABLE `zhangshuo` ( `id` int(11) NOT NULL DEFAULT '0', `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), KEY `name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec)
聚集索引的選擇:
a,含有大量非重復值的列;
b,被連續(順序)訪問的列;
c,返回大量結果集的查詢;
案例:
如果一個表很大,有1/3數據要刪除,如果是隨機刪除,會產很多空洞,刪完后產生的空洞不寫入,沒什么影響,但這種刪除比較慢,因為需要對btree進行隨機掃描。刪完后索引樹會進行自旋,如果它的page填充因子比較低,例如把2頁合並成1頁,在合並中進行寫入會比較慢。 刪完后可以執行alter table engine=innodb來整理碎片,但是會鎖表(重建整張表)或者重新定義主鍵列。建議使用pt-osc來完成表空間回收。
innodb主鍵索引分布:
第一列:主鍵鍵值
第二列:事物ID
第三列:回滾指針
第四行:除了主鍵列以外其他列的值
innodb普通非唯一索引分布:
第一列是索引鍵值,因為是普通索引所以存在重復。
第二列是主鍵的列值。
innodb普通索引的key是本身列值,value對應的是主鍵的鍵值。這樣做的目的是我們通過普通索引來掃描數據的時候我們可以快速的通過普通索引存儲的主鍵的鍵值找到對應的記錄。
innodb 主鍵索引特點:(這個表可以理解成6行3個列)
普通索引的value指向的是主鍵的列:
innodb聚集索引特點驗證: