Mysql中常用的兩個(gè)存儲引擎innodb和mysiam的索引是不同的。
聚集索引就是以主鍵創(chuàng)建的索引
非聚集索引就是除了主鍵以外的索引。
非聚集索引也叫做二級索引,不用糾結(jié)那么多名詞,將其等價(jià)就行了。非聚集索引在建立的時(shí)候也未必是單列的,可以多個(gè)列來創(chuàng)建索引。
關(guān)于mysiam和innoDB的特性及區(qū)別,我在下邊放了一張圖:
想了解更多,請移步《mysql(二十八)之MySQL中的鎖 --- MyISAM引擎》《mysql(二十九)之MySQL中的鎖InnoDB引擎》
在數(shù)據(jù)庫中,B+樹的高度一般都在2到4層,這也就是說查找某一個(gè)鍵值的行記錄時(shí)最多只需要2到4次IO,這倒不錯(cuò)。因?yàn)楫?dāng)前一般的機(jī)械硬盤每秒至少可以做100次IO,24次的IO意味著查詢時(shí)間只需要0.02~0.04秒。
數(shù)據(jù)庫中的B+樹索引可以分為聚集索引(clustered index)和輔助索引(secondary index)。
聚集索引與輔助索引相同的是:不管是聚集索引還是輔助索引,其內(nèi)部都是B+樹的形式,即高度是平衡的,葉子結(jié)點(diǎn)存放著所有的數(shù)據(jù)。
聚集索引與輔助索引不同的是:輔助索引的葉子節(jié)點(diǎn)不包含行記錄的全部數(shù)據(jù)
一:非聚集索引(輔助索引)
Mysiam創(chuàng)建數(shù)據(jù)表的時(shí)候,會在磁盤上生成三個(gè).frm.MYD.MYI結(jié)尾的三個(gè)文件,frm結(jié)尾的是表結(jié)構(gòu),MYD結(jié)尾的是數(shù)據(jù)文件,MYI結(jié)尾的就是索引文件,也就是說索引也是存在硬盤上的。
葉子節(jié)點(diǎn)存放的是對應(yīng)的那條數(shù)據(jù)的主鍵字段的值,除了包含鍵值以外,每個(gè)葉子節(jié)點(diǎn)中的索引行中還包含一個(gè)書簽(bookmark),其實(shí)這個(gè)書簽?zāi)憧梢岳斫鉃槭且粋€(gè){'name字段',name的值,主鍵id值}的這么一個(gè)數(shù)據(jù)。
該書簽用來告訴InnoDB存儲引擎去哪里可以找到與索引相對應(yīng)的行數(shù)據(jù)。如果我們select 后面要的是name,我們直接就可以在輔助索引的葉子節(jié)點(diǎn)找到對應(yīng)的name值,比如:select name from tb1 where name='xx';
這個(gè)xx值你直接就在輔助索引的葉子節(jié)點(diǎn)就能找到,這種我們也可以稱為覆蓋索引。如果你select后面的字段不是name,例如:select age from tb1 where name='xx';
也就是說,我通過輔助索引的葉子節(jié)點(diǎn)不能直接拿到age的值,需要通過輔助索引的葉子節(jié)點(diǎn)中保存的主鍵id的值再去通過聚集索引來找到完整的一條記錄,然后從這個(gè)記錄里面拿出age的值,這種操作有時(shí)候也成為回表操作,就是從頭再回去查一遍,這種的查詢效率也很高,但是比覆蓋索引低一些,再說一下昂,再輔助索引的葉子節(jié)點(diǎn)就能找到你想找的數(shù)據(jù)可稱為覆蓋索引。
二:聚集性索引
InnoDB 在 B+ 樹數(shù)據(jù)結(jié)構(gòu)中索引又分為聚集索引和輔助索引
InnoDB創(chuàng)建數(shù)據(jù)表的時(shí)候,會在磁盤上生成.frm.idb結(jié)尾的兩個(gè)文件。
索引存儲在.idb結(jié)尾的數(shù)據(jù)文件中,InnoDB引擎的表,它的索引和數(shù)據(jù)都在同一個(gè)文件里面,所以我一直強(qiáng)調(diào),使用InnoDB存儲引擎的時(shí)候,每建一個(gè)表,就需要給一個(gè)主鍵,是因?yàn)檫@個(gè)主鍵是InnoDB存儲引擎的.idb文件來組織存儲數(shù)據(jù)的依據(jù)或者說方式,也就是說InnoDB存儲引擎在存儲數(shù)據(jù)的時(shí)候默認(rèn)就按照索引的那種樹形結(jié)構(gòu)來幫你存。
這種索引,我們就稱為聚集索引,也就是在聚集數(shù)據(jù)組織數(shù)據(jù)的時(shí)候,就用這種索引。
InnoDB這么做就是為了加速查詢效率,因?yàn)槟憬?jīng)常會遇到基于主鍵來查詢數(shù)據(jù)的情況,并且通常我們把id字段作為主鍵,第一點(diǎn)是因?yàn)閕d占用的數(shù)據(jù)空間不大,第二點(diǎn)是你經(jīng)常會用到id來查數(shù)據(jù)。
如果你的表有兩個(gè)字段,一個(gè)id一個(gè)name,id為主鍵,當(dāng)你查詢的時(shí)候如果where后面的條件是name=多少多少,那么你就沒有用到主鍵給你帶來的加速查詢的效果(需要主鍵之外的輔助索引),如果你用where id=多少多少,就會按照我們剛才上面說的哪種樹形結(jié)構(gòu)來給你找尋數(shù)據(jù)了(當(dāng)然不僅僅有這種樹形結(jié)構(gòu)的數(shù)據(jù)結(jié)構(gòu)類型),能夠快速的幫你定位到數(shù)據(jù)塊。
這種聚集索引的特點(diǎn)是它會以id字段作為依據(jù),去建立樹形結(jié)構(gòu),但是葉子節(jié)點(diǎn)存的是你表中的一條完整記錄,一條完整的數(shù)據(jù)。
聚集索引的特性:
InnoDB存儲引擎表示索引組織表,即表中數(shù)據(jù)按照主鍵順序存放。而聚集索引(clustered index)就是按照每張表的主鍵構(gòu)造一棵B+樹,同時(shí)葉子結(jié)點(diǎn)存放的即為整張表的行記錄數(shù)據(jù),也將聚集索引的葉子結(jié)點(diǎn)稱為數(shù)據(jù)頁。聚集索引的這個(gè)特性決定了索引組織表中數(shù)據(jù)也是索引的一部分。同B+樹數(shù)據(jù)結(jié)構(gòu)一樣,每個(gè)數(shù)據(jù)頁都通過一個(gè)雙向鏈表來進(jìn)行鏈接。
如果未定義主鍵,MySQL取第一個(gè)唯一索引(unique)而且只含非空列(NOT NULL)作為主鍵,InnoDB使用它作為聚簇索引。
如果沒有這樣的列,InnoDB就自己產(chǎn)生一個(gè)這樣的ID值,它有六個(gè)字節(jié),而且是隱藏的,使其作為聚簇索引。
由于實(shí)際的數(shù)據(jù)頁只能按照一棵B+樹進(jìn)行排序,因此每張表只能擁有一個(gè)聚集索引。在多少情況下,查詢優(yōu)化器傾向于采用聚集索引。因?yàn)榫奂饕軌蛟贐+樹索引的葉子節(jié)點(diǎn)上直接找到數(shù)據(jù)。此外由于定義了數(shù)據(jù)的邏輯順序,聚集索引能夠特別快地訪問針對范圍值得查詢。
三:關(guān)于索引的建議
1: 單表索引不超過六個(gè)
2: 不建議使用過長的字段作為主鍵,因?yàn)樗休o助索引都引用主索引,過長的主索引會令輔助索引變得過大。
3: 用非單調(diào)的字段作為主鍵在InnoDB中不是個(gè)好主意,因?yàn)镮nnoDB數(shù)據(jù)文件本身是一顆B+Tree,非單調(diào)的主鍵會造成在插入新記錄時(shí)數(shù)據(jù)文件為了維持B+Tree的特性而頻繁的分裂調(diào)整,十分低效,而使用自增字段作為主鍵則是一個(gè)很好的選擇。
有好的建議,請?jiān)谙路捷斎肽愕脑u論。
歡迎訪問個(gè)人博客
https://guanchao.site