聚集索引和非聚集索引

2021-09-11 00:11:51 字數 4198 閱讀 3106

當我們被問到「資料庫資料幾十萬過多,查詢較慢,該使用哪種方法提高查詢方法」,答案:建立聚集索引非聚集索引。

方便自己檢視理解,以下內容**

聚集索引與非聚集索引的總結

一.索引簡介

眾所周知,索引是關係型資料庫中給資料庫表中一列或多列的值排序後的儲存結構,sql的主流索引結構有b+樹以及hash結構,聚集索引以及非聚集索引用的是b+樹索引。這篇文章會總結sql server以及mysql的innodb和myisam兩種sql的索引。

sql sever索引型別有:唯一索引,主鍵索引,聚集索引,非聚集索引`。

mysql 索引型別有:唯一索引,主鍵(聚集)索引,非聚集索引,全文索引。

二.聚集索引聚集(clustered)索引,也叫聚簇索引。

定義:資料行的物理順序與列值(一般是主鍵的那一列)的邏輯順序相同,乙個表中只能擁有乙個聚集索引。
單單從定義來看是不是顯得有點抽象,打個比方,乙個表就像是我們以前用的新華字典,聚集索引就像是拼音目錄,而每個字存放的頁碼就是我們的資料實體地址,我們如果要查詢乙個「哇」字,我們只需要查詢「哇」字對應在新華字典拼音目錄對應的頁碼,就可以查詢到對應的「哇」字所在的位置,而拼音目錄對應的a-z的字順序,和新華字典實際儲存的字的順序a-z也是一樣的,如果我們中文新出了乙個字,拼音開頭第乙個是b,那麼他插入的時候也要按照拼音目錄順序插入到a字的後面,現在用乙個簡單的示意圖來大概說明一下在資料庫中的樣子:

位址 id username score

0x01 1 小明 90

0x02 2 小紅 80

0x03 3 小華 92

… … … …

0xff 256 小英 70

注:第一列的位址表示該行資料在磁碟中的實體地址,後面三列才是我們sql裡面用的表裡的列,其中id是主鍵,建立了聚集索引。

結合上面的**就可以理解這句話了吧:資料行的物理順序與列值的順序相同,如果我們查詢id比較靠後的資料,那麼這行資料的位址在磁碟中的實體地址也會比較靠後。而且由於物理排列方式與聚集索引的順序相同,所以也就只能建立乙個聚集索引了。

聚集索引實際存放的示意圖

從上圖可以看出聚集索引的好處了,索引的葉子節點就是對應的資料節點(mysql的myisam除外,此儲存引擎的聚集索引和非聚集索引只多了個唯一約束,其他沒什麼區別),可以直接獲取到對應的全部列的資料,而非聚集索引在索引沒有覆蓋到對應的列的時候需要進行二次查詢,後面會詳細講。因此在查詢方面,聚集索引的速度往往會更佔優勢。

建立聚集索引

如果不建立索引,系統會自動建立乙個隱含列作為表的聚集索引。

1.建立表的時候指定主鍵(注意:sql sever預設主鍵為聚集索引,也可以指定為非聚集索引,而mysql裡主鍵就是聚集索引)

create table t1(

id int primary key,

name nvarchar(255)

)

2.建立表後新增聚集索引

sql server

create clustered index clustered_index on table_name(colum_name)
mysql

alter table table_name add primary key(colum_name)
值得注意的是,最好還是在建立表的時候新增聚集索引,由於聚集索引的物理順序上的特殊性,因此如果再在上面建立索引的時候會根據索引列的排序移動全部資料行上面的順序,會非常地耗費時間以及效能。

三.非聚集索引

非聚集(unclustered)索引。

定義:該索引中索引的邏輯順序與磁碟上行的物理儲存順序不同,乙個表中可以擁有多個非聚集索引。
其實按照定義,除了聚集索引以外的索引都是非聚集索引,只是人們想細分一下非聚集索引,分成普通索引,唯一索引,全文索引。如果非要把非聚集索引模擬成現實生活中的東西,那麼非聚集索引就像新華字典的偏旁字典,他結構順序與實際存放順序不一定一致。

非聚集索引實際存放的示意圖

非聚集索引的二次查詢問題

非聚集索引葉節點仍然是索引節點,只是有乙個指標指向對應的資料塊,此如果使用非聚集索引查詢,而查詢列中包含了其他該索引沒有覆蓋的列,那麼他還要進行第二次的查詢,查詢節點上對應的資料行的資料。

如有以下表t1:

id username score

1 小明 90

2 小紅 80

3 小華 92

… … …

256 小英 70

以及聚集索引clustered index(id), 非聚集索引index(username)。

使用以下語句進行查詢,不需要進行二次查詢,直接就可以從非聚集索引的節點裡面就可以獲取到查詢列的資料。

select id, username from t1 where username = '小明'

select username from t1 where username = '小明'

但是使用以下語句進行

查詢,就需要二次的查詢去獲取原資料行的score:

select username, score from t1 where username = '小明'
在sql server裡面查詢效率如下所示,index seek就是索引所花費的時間,key lookup就是二次查詢所花費的時間。可以看的出二次查詢所花費的查詢開銷佔比很大,達到50%。

在sql server裡面會對查詢自動優化,選擇適合的索引,因此如果在資料量不大的情況下,sql server很有可能不會使用非聚集索引進行查詢,而是使用聚集索引進行查詢,即便需要掃瞄整個聚集索引,效率也比使用非聚集索引效率要高。

本人試過在含有30w行表上建立非聚集索引,查詢非聚集索引覆蓋以外的列就會變成聚集索引的全索引掃瞄(index scan)查詢來避免二次查詢,而在另外一張200w行表才會用到非聚集索引seek對應的列再進行kek lookup,有關於sql server的有index seek,index scan, table scan,key lookup這幾個概念,可以檢視這個blog,描寫比較詳細。

但在mysql裡面就算表裡資料量少且查詢了非鍵列,也不會使用聚集索引去全索引掃瞄,但如果強制使用聚集索引去查詢,效能反而比非聚集索引查詢要差,這就是兩種sql的不同之處。

還有一點要注意的是非聚集索引其實葉子節點除了會儲存索引覆蓋列的資料,也會存放聚集索引所覆蓋的列資料。

如何解決非聚集索引的二次查詢問題

復合索引(覆蓋索引)

建立兩列以上的索引,即可查詢復合索引裡的列的資料而不需要進行回表二次查詢,如index(col1, col2),執行下面的語句

select col1, col2 from t1 where col1 = '213';
要注意使用復合索引需要滿足最左側索引的原則,也就是查詢的時候如果where條件裡面沒有最左邊的一到多列,索引就不會起作用。

在sql server中還有include的用法,可以把非聚集索引裡包含的列包含進來,而不一定需要建立復合索引。

四.總結與使用心得

使用聚集索引的查詢效率要比非聚集索引的效率要高,但是如果需要頻繁去改變聚集索引的值,寫入效能並不高,因為需要移動對應資料的物理位置。

非聚集索引在查詢的時候可以的話就避免二次查詢,這樣效能會大幅提公升。

不是所有的表都適合建立索引,只有資料量大表才適合建立索引,且建立在選擇性高的列上面效能會更好。

聚集索引和非聚集索引

聚集索引和非聚集索引 一 聚集索引和非聚集索引 聚集索引和非聚集索引的根本區別是表記錄的排列順序和與索引的排列順序是否一致,聚集索引表記錄的排列順序與索引的排列順序一致,優點是查詢速度快,因為一旦具有第乙個索引值的紀錄被找到,具有連續索引值的記錄也一定物理的緊跟其後。聚集索引的缺點是對錶進行修改速度...

聚集索引和非聚集索引

本文引自 一種索引,該索引中鍵值的邏輯順序決定了表中相應行的物理順序。聚集索引確定表中資料的物理順序。聚集索引類似於 簿,後者按姓氏排列資料。由於聚集索引規定資料在表中的物理儲存順序,因此乙個表只能包含乙個聚集索引。但該索引可以包含多個列 組合索引 就像 簿按姓氏和名字進行組織一樣。聚集索引對於那些...

聚集索引和非聚集索引

聚集索引和非聚集索引 1 聚集索引 聚集索引,表中的資料儲存位置,根據索引的排序進行實際儲存,因此效率是相當高的。因為聚集索引決定了表中資料行的儲存位置。乙個表不可能有兩個或以上的聚集索引,如果乙個表中已經有乙個聚集索引,那麼這個表中其他的索引都將是非聚集索引。表排列順序 表記錄的排列順序與索引的排...