聚簇索引、非聚簇索引、普通索引、唯一索引
一、聚簇索引 VS 非聚簇索引
- 聚簇索引:將數(shù)據(jù)存儲(chǔ)與索引放到了一塊,找到索引也就找到了數(shù)據(jù)
- 非聚簇索引:將數(shù)據(jù)存儲(chǔ)于索引分開結(jié)構(gòu),索引結(jié)構(gòu)的葉子節(jié)點(diǎn)指向了數(shù)據(jù)的對(duì)應(yīng)行,myisam通過key_buffer把索引先緩存到內(nèi)存中,當(dāng)需要訪問數(shù)據(jù)時(shí)(通過索引訪問數(shù)據(jù)),在內(nèi)存中直接搜索索引,然后通過索引找到磁盤相應(yīng)數(shù)據(jù),這也就是為什么索引不在key buffer命中時(shí),速度慢的原因
澄清一個(gè)概念:innodb中,在聚簇索引之上創(chuàng)建的索引稱之為輔助索引,輔助索引訪問數(shù)據(jù)總是需要二次查找(回表),非聚簇索引都是輔助索引,像復(fù)合索引、前綴索引、唯一索引,輔助索引葉子節(jié)點(diǎn)存儲(chǔ)的不再是行的物理位置,而是主鍵值。
二、何時(shí)使用聚簇索引與非聚簇索引
由于聚簇索引是將數(shù)據(jù)跟索引結(jié)構(gòu)放到一塊,因此一個(gè)表僅有一個(gè)聚簇索引
聚簇索引默認(rèn)是主鍵,如果表中沒有定義主鍵,InnoDB 會(huì)選擇一個(gè)唯一的非空索引代替。如果沒有這樣的索引,InnoDB 會(huì)隱式定義一個(gè)主鍵來作為聚簇索引。InnoDB 只聚集在同一個(gè)頁(yè)面中的記錄。包含相鄰鍵值的頁(yè)面可能相距甚遠(yuǎn)。如果你已經(jīng)設(shè)置了主鍵為聚簇索引,必須先刪除主鍵,然后添加我們想要的聚簇索引,最后恢復(fù)設(shè)置主鍵即可。此時(shí)其他索引只能被定義為非聚簇索引。這個(gè)是最大的誤區(qū)。有的主鍵還是無意義的自動(dòng)增量字段,那樣的話Clustered index對(duì)效率的幫助,完全被浪費(fèi)了。剛才說到了,聚簇索引性能最好而且具有唯一性,所以非常珍貴,必須慎重設(shè)置。一般要根據(jù)這個(gè)表最常用的SQL查詢方式來進(jìn)行選擇,某個(gè)字段作為聚簇索引,或組合聚簇索引,這個(gè)要看實(shí)際情況。記住我們的最終目的就是在相同結(jié)果集情況下,盡可能減少邏輯IO。
- InnoDB使用的是聚簇索引,將主鍵組織到一棵B+樹中,而行數(shù)據(jù)就儲(chǔ)存在葉子節(jié)點(diǎn)上,若使用"where id = 14"這樣的條件查找主鍵,則按照B+樹的檢索算法即可查找到對(duì)應(yīng)的葉節(jié)點(diǎn),之后獲得行數(shù)據(jù)。
- 若對(duì)Name列進(jìn)行條件搜索,則需要兩個(gè)步驟:第一步在輔助索引B+樹中檢索Name,到達(dá)其葉子節(jié)點(diǎn)獲取對(duì)應(yīng)的主鍵。第二步使用主鍵在主索引B+樹種再執(zhí)行一次B+樹檢索操作,最終到達(dá)葉子節(jié)點(diǎn)即可獲取整行數(shù)據(jù)。(重點(diǎn)在于通過其他鍵需要建立輔助索引)
MyISM使用的是非聚簇索引,非聚簇索引的兩棵B+樹看上去沒什么不同,節(jié)點(diǎn)的結(jié)構(gòu)完全一致只是存儲(chǔ)的內(nèi)容不同而已,主鍵索引B+樹的節(jié)點(diǎn)存儲(chǔ)了主鍵,輔助鍵索引B+樹存儲(chǔ)了輔助鍵。表數(shù)據(jù)存儲(chǔ)在獨(dú)立的地方,這兩顆B+樹的葉子節(jié)點(diǎn)都使用一個(gè)地址指向真正的表數(shù)據(jù),對(duì)于表數(shù)據(jù)來說,這兩個(gè)鍵沒有任何差別。由于索引樹是獨(dú)立的,通過輔助鍵檢索無需訪問主鍵的索引樹。
三、聚簇索引的優(yōu)勢(shì)
看上去聚簇索引的效率明顯要低于非聚簇索引,因?yàn)槊看问褂幂o助索引檢索都要經(jīng)過兩次B+樹查找,這不是多此一舉嗎?聚簇索引的優(yōu)勢(shì)在哪?
四、聚簇索引的劣勢(shì)
所以建議使用int的auto_increment作為主鍵
主鍵的值是順序的,所以 InnoDB 把每一條記錄都存儲(chǔ)在上一條記錄的后面。當(dāng)達(dá)到頁(yè)的最大填充因子時(shí)(InnoDB 默認(rèn)的最大填充因子是頁(yè)大小的 15/16,留出部分空間用于以后修改),下一條記錄就會(huì)寫入新的頁(yè)中。一旦數(shù)據(jù)按照這種順序的方式加載,主鍵頁(yè)就會(huì)近似于被順序的記錄填滿(二級(jí)索引頁(yè)可能是不一樣的)。如果主鍵比較大的話,那輔助索引將會(huì)變的更大,因?yàn)檩o助索引的葉子存儲(chǔ)的是主鍵值;過長(zhǎng)的主鍵值,會(huì)導(dǎo)致非葉子節(jié)點(diǎn)占用占用更多的物理空間
五、為什么主鍵通常建議使用自增id
聚簇索引的數(shù)據(jù)的物理存放順序與索引順序是一致的,即:只要索引是相鄰的,那么對(duì)應(yīng)的數(shù)據(jù)一定也是相鄰地存放在磁盤上的。如果主鍵不是自增id,那么可以想象,它會(huì)干些什么,不斷地調(diào)整數(shù)據(jù)的物理地址、分頁(yè),當(dāng)然也有其他一些措施來減少這些操作,但卻無法徹底避免。但,如果是自增的,那就簡(jiǎn)單了,它只需要一 頁(yè)一頁(yè)地寫,索引結(jié)構(gòu)相對(duì)緊湊,磁盤碎片少,效率也高。因?yàn)镸yISAM的主索引并非聚簇索引,那么他的數(shù)據(jù)的物理地址必然是凌亂的,拿到這些物理地址,按照合適的算法進(jìn)行I/O讀取,于是開始不停的尋道不停的旋轉(zhuǎn)。聚簇索引則只需一次I/O。(強(qiáng)烈的對(duì)比)。不過,如果涉及到大數(shù)據(jù)量的排序、全表掃描、count之類的操作的話,還是MyISAM占優(yōu)勢(shì)些,因?yàn)樗饕伎臻g小,這些操作是需要在內(nèi)存中完成的。
六、mysql中聚簇索引的設(shè)定
聚簇索引默認(rèn)是主鍵,如果表中沒有定義主鍵,InnoDB 會(huì)選擇一個(gè)唯一的非空索引代替。如果沒有這樣的索引,InnoDB 會(huì)隱式定義一個(gè)主鍵來作為聚簇索引。InnoDB 只聚集在同一個(gè)頁(yè)面中的記錄。包含相鄰健值的頁(yè)面可能相距甚遠(yuǎn)。
七、普通索引
由key或者index定義,允許被索引的數(shù)據(jù)列包含重復(fù)數(shù)值,例如普通索引index(id,nane),id=1,name=a;id=2,name=a)是可以存在的。普通索引主要目的就是提高數(shù)據(jù)訪問速度。
八、唯一索引
由unique定義,不允許被索引的數(shù)據(jù)列包含重復(fù)數(shù)值。主鍵索引是一種特殊的唯一索引,由primary key定義
九、例子
mysql> create table user(-> id int(10) auto_increment,-> name varchar(30),-> age tinyint(4),# 主鍵索引,唯一索引-> primary key (id),# 唯一索引-> index idx_age (age)//注意此處建立了age的索引-> )engine=innodb charset=utf8mb4;# 聯(lián)合索引,普通索引-> create index ind_age_name on user(age,name);文章部分轉(zhuǎn)自
總結(jié)
以上是生活随笔為你收集整理的聚簇索引、非聚簇索引、普通索引、唯一索引的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mysql8.0之后没有缓存功能
- 下一篇: 互联网日报 | 3月20日 星期六 |