B+樹
我們這裏關注B+樹的兩個特性:
葉子節點包含數據data(data並不特指數據庫中的某一行數據,也可以是某個數值,指針等)
葉子節點均在同一層,且每個節點均可以直接找到上一個或者下一個節點(雙向指針,比常規的B+樹多了一個指向上一個的指針)
4階 B+樹
InnoDB 聚簇索引
聚簇索引:行數據與鍵值(主鍵)緊湊地存儲在一起;
InnoDB中表現爲:B+樹葉子節點的data用於存放行數據(包含主鍵值、其他列數據、回滾指針、事務id等),物理上索引數據與行數據都放在同一個文件中(.ibd
)
以用戶表爲例,id
爲主鍵,另外name存在索引idx_name
:
CREATE TABLE `t_user` ( `id` bigint, `name` varchar(10), `age` int, PRIMARY KEY (`id`), KEY `idx_name` (`name`) );
插入數據:
insert into t_user (id,`name`,age) values(1,'n7',10), (2,'n6',20), (3,'n5',30), (4,'n4',40), (5,'n3',50), (6,'n2',60), (7,'n1',70)
聚簇索引對應的結構爲:
InnoDB聚簇索引,注:數據庫中B+樹的階數要比這個大得多
如果沒有定義主鍵,InnoDB會選擇一個唯一的非空索引代替。如果沒有這樣的索引,InnoDB會隱式定義一個主鍵(DB_ROW_ID)來作爲聚簇索引。
最好避免使用隨機的主鍵(比如UUID)
InnoDB中磁盤管理的最小單位爲頁(InnoDB page,默認16KB),一頁能存放的數據記錄數量是有限的,根據B+樹的特性,需要保證頁內數據是按主鍵排序存儲的。
當主鍵隨機插入時,如果新的記錄可能需要插入之前記錄的中間,導致需要強制移動之前的記錄;如果需要插入一個已經滿了的頁中時,會導致頁分裂(新建兩個頁並把原數據複製過去,成本很高)。
InnoDB 二級索引
二級索引,或者叫非聚簇索引;與聚簇索引最大的不同是:B+樹的data存放的並不是行數據,而是主鍵值;
以上面用戶表爲例,當select * from t_user where name='n1'
時,會先通過idx_name
索引找到n2
對應的主鍵的值(id=7),再通過主鍵值找到行數據 [7,n1,70] ,故稱二級索引。
InnoDB二級索引
覆蓋索引:當select的列的已經在二級索引的樹中時,並不需要再通過主鍵值找到整行的數據即可返回。比如
select id,name from t_user where name='n2'
,name和id均可在idx_name
索引的葉子節點上,故不用主鍵回查聚簇索引了。像這種二級索引覆蓋到所有查詢列數據的情況叫覆蓋索引。使用explain
這個查詢時可以看到Extra
中包含Using index
MyISAM 索引
與InnoDB不同,MyISAM並不使用聚簇索引,MyISAM的索引數據和行數據是分開的,物理上分別爲.myi
索引數據文件和.myd
行數據文件(InnoDB 索引和行數據均在.idb
文件中)
MyISAM中,主鍵索引和其他的一般索引在數據結構上並沒有什麼區別,B+樹的data存放的均是數據行地址。
id主鍵索引:
MyISAM主鍵索引
name一般索引:
MyISAM一般索引