聚集索引與非聚集索引

一.索引簡介

眾所周知凫海,索引是關系型數(shù)據(jù)庫中給數(shù)據(jù)庫表中一列或多列的值排序后的存儲結構瀑凝,SQL的主流索引結構有B+樹以及Hash結構歼冰,聚集索引以及非聚集索引用的是B+樹索引凰萨。這篇文章會總結SQL Server以及MySQL的InnoDB和MyISAM兩種SQL的索引。

SQL Sever索引類型有:唯一索引侦高,主鍵索引,聚集索引厌杜,非聚集索引奉呛。

MySQL 索引類型有:唯一索引,主鍵(聚集)索引夯尽,非聚集索引瞧壮,全文索引。

二.聚集索引

聚集(clustered)索引匙握,也叫聚簇索引咆槽。

定義:數(shù)據(jù)行的物理順序與列值(一般是主鍵的那一列)的邏輯順序相同,一個表中只能擁有一個聚集索引圈纺。

單單從定義來看是不是顯得有點抽象秦忿,打個比方麦射,一個表就像是我們以前用的新華字典,聚集索引就像是拼音目錄灯谣,而每個字存放的頁碼就是我們的數(shù)據(jù)物理地址潜秋,我們如果要查詢一個“哇”字,我們只需要查詢“哇”字對應在新華字典拼音目錄對應的頁碼胎许,就可以查詢到對應的“哇”字所在的位置峻呛,而拼音目錄對應的A-Z的字順序,和新華字典實際存儲的字的順序A-Z也是一樣的辜窑,如果我們中文新出了一個字钩述,拼音開頭第一個是B,那么他插入的時候也要按照拼音目錄順序插入到A字的后面穆碎,現(xiàn)在用一個簡單的示意圖來大概說明一下在數(shù)據(jù)庫中的樣子:

地址 id username score
0x01 1 小明 90
0x02 2 小紅 80
0x03 3 小華 92
.. .. .. ..
0xff 256 小英 70

注:第一列的地址表示該行數(shù)據(jù)在磁盤中的物理地址牙勘,后面三列才是我們SQL里面用的表里的列,其中id是主鍵惨远,建立了聚集索引谜悟。

結合上面的表格就可以理解這句話了吧:數(shù)據(jù)行的物理順序與列值的順序相同,如果我們查詢id比較靠后的數(shù)據(jù)北秽,那么這行數(shù)據(jù)的地址在磁盤中的物理地址也會比較靠后葡幸。而且由于物理排列方式與聚集索引的順序相同,所以也就只能建立一個聚集索引了贺氓。

image

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

從上圖可以看出聚集索引的好處了蔚叨,索引的葉子節(jié)點就是對應的數(shù)據(jù)節(jié)點(MySQL的MyISAM除外,此存儲引擎的聚集索引和非聚集索引只多了個唯一約束辙培,其他沒什么區(qū)別)蔑水,可以直接獲取到對應的全部列的數(shù)據(jù),而非聚集索引在索引沒有覆蓋到對應的列的時候需要進行二次查詢扬蕊,后面會詳細講搀别。因此在查詢方面,聚集索引的速度往往會更占優(yōu)勢尾抑。

創(chuàng)建聚集索引

如果不創(chuàng)建索引歇父,系統(tǒng)會自動創(chuàng)建一個隱含列作為表的聚集索引。

1.創(chuàng)建表的時候指定主鍵(注意:SQL Sever默認主鍵為聚集索引再愈,也可以指定為非聚集索引榜苫,而MySQL里主鍵就是聚集索引)

create table t1(
    id int primary key,
    name nvarchar(255)
)

2.創(chuàng)建表后添加聚集索引

SQL Server

create clustered index clustered_index on table_name(colum_name)

MySQL

alter table table_name add primary key(colum_name)

值得注意的是,最好還是在創(chuàng)建表的時候添加聚集索引翎冲,由于聚集索引的物理順序上的特殊性垂睬,因此如果再在上面創(chuàng)建索引的時候會根據(jù)索引列的排序移動全部數(shù)據(jù)行上面的順序,會非常地耗費時間以及性能。

三.非聚集索引

非聚集(unclustered)索引驹饺。

定義:該索引中索引的邏輯順序與磁盤上行的物理存儲順序不同钳枕,一個表中可以擁有多個非聚集索引。

其實按照定義逻淌,除了聚集索引以外的索引都是非聚集索引么伯,只是人們想細分一下非聚集索引,分成普通索引卡儒,唯一索引田柔,全文索引。如果非要把非聚集索引類比成現(xiàn)實生活中的東西骨望,那么非聚集索引就像新華字典的偏旁字典硬爆,他結構順序與實際存放順序不一定一致。

image

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

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

非聚集索引葉節(jié)點仍然是索引節(jié)點擎鸠,只是有一個指針指向對應的數(shù)據(jù)塊缀磕,此如果使用非聚集索引查詢,而查詢列中包含了其他該索引沒有覆蓋的列劣光,那么他還要進行第二次的查詢袜蚕,查詢節(jié)點上對應的數(shù)據(jù)行的數(shù)據(jù)。

如有以下表t1:

id username score
1 小明 90
2 小紅 80
3 小華 92
.. .. ..
256 小英 70

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

使用以下語句進行查詢牲剃,不需要進行二次查詢,直接就可以從非聚集索引的節(jié)點里面就可以獲取到查詢列的數(shù)據(jù)雄可。

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

但是使用以下語句進行查詢凿傅,就需要二次的查詢去獲取原數(shù)據(jù)行的score:

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

在SQL Server里面查詢效率如下所示,Index Seek就是索引所花費的時間数苫,Key Lookup就是二次查詢所花費的時間聪舒。可以看的出二次查詢所花費的查詢開銷占比很大虐急,達到50%箱残。

image

在SQL Server里面會對查詢自動優(yōu)化,選擇適合的索引止吁,因此如果在數(shù)據(jù)量不大的情況下被辑,SQL Server很有可能不會使用非聚集索引進行查詢,而是使用聚集索引進行查詢敷待,即便需要掃描整個聚集索引仁热,效率也比使用非聚集索引效率要高。

image

本人試過在含有30w行表上建立非聚集索引举哟,查詢非聚集索引覆蓋以外的列就會變成聚集索引的全索引掃描(index scan)查詢來避免二次查詢迅矛,而在另外一張200w行表才會用到非聚集索引seek對應的列再進行kek lookup,有關于SQL Server的有Index seek壶硅,index scan, table scan销斟,key LookUp這幾個概念,可以查看這個blog约谈,描寫比較詳細犁钟。

但在MySQL里面就算表里數(shù)據(jù)量少且查詢了非鍵列,也不會使用聚集索引去全索引掃描迈勋,但如果強制使用聚集索引去查詢捧存,性能反而比非聚集索引查詢要差,這就是兩種SQL的不同之處昔穴。

還有一點要注意的是非聚集索引其實葉子節(jié)點除了會存儲索引覆蓋列的數(shù)據(jù),也會存放聚集索引所覆蓋的列數(shù)據(jù)泳唠。

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

復合索引(覆蓋索引)

建立兩列以上的索引宙搬,即可查詢復合索引里的列的數(shù)據(jù)而不需要進行回表二次查詢,如index(col1, col2)脖母,執(zhí)行下面的語句

select col1, col2 from t1 where col1 = '213';

要注意使用復合索引需要滿足最左側索引的原則闲孤,也就是查詢的時候如果where條件里面沒有最左邊的一到多列,索引就不會起作用肥照。

在SQL Server中還有include的用法,可以把非聚集索引里包含的列包含進來舆绎,而不一定需要建立復合索引吕朵。

四.總結與使用心得

  1. 使用聚集索引的查詢效率要比非聚集索引的效率要高,但是如果需要頻繁去改變聚集索引的值努溃,寫入性能并不高茅坛,因為需要移動對應數(shù)據(jù)的物理位置。
  2. 非聚集索引在查詢的時候可以的話就避免二次查詢贡蓖,這樣性能會大幅提升。
  3. 不是所有的表都適合建立索引彻桃,只有數(shù)據(jù)量大表才適合建立索引晾蜘,且建立在選擇性高的列上面性能會更好。
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末肆饶,一起剝皮案震驚了整個濱河市岖常,隨后出現(xiàn)的幾起案子竭鞍,更是在濱河造成了極大的恐慌,老刑警劉巖偎快,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晒夹,死亡現(xiàn)場離奇詭異妖异,居然都是意外死亡领追,警方通過查閱死者的電腦和手機绒窑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門舔亭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人订雾,你說我怎么就攤上這事矛洞。” “怎么了噩峦?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵识补,是天一觀的道長辫红。 經(jīng)常有香客問我,道長切油,這世上最難降的妖魔是什么名惩? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮绢片,結果婚禮上,老公的妹妹穿的比我還像新娘巢株。我一直安慰自己熙涤,他們只是感情好困檩,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布悼沿。 她就那樣靜靜地躺著骚灸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪义郑。 梳的紋絲不亂的頭發(fā)上丈钙,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天,我揣著相機與錄音劫笙,去河邊找鬼星岗。 笑死伍茄,一個胖子當著我的面吹牛,可吹牛的內容都是我干的敷矫。 我是一名探鬼主播曹仗,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼怎茫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蜜宪?” 一聲冷哼從身側響起祥山,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤缝呕,失蹤者是張志新(化名)和其女友劉穎斧散,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體摊聋,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡麻裁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年悲立,在試婚紗的時候發(fā)現(xiàn)自己被綠了薪夕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赫悄。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡埂淮,死狀恐怖,靈堂內的尸體忽然破棺而出讲仰,到底是詐尸還是另有隱情鄙陡,我是刑警寧澤躏啰,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布给僵,位于F島的核電站,受9級特大地震影響帝际,放射性物質發(fā)生泄漏。R本人自食惡果不足惜蹲诀,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望侧甫。 院中可真熱鬧,春花似錦咒锻、人聲如沸惑艇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜈垮。三九已至,卻和暖如春调塌,著一層夾襖步出監(jiān)牢的瞬間惠猿,已是汗流浹背偶妖。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工餐屎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人屿聋。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像楚殿,于是被迫代替她去往敵國和親竿痰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內容

  • 聚集索引與非聚集索引 數(shù)據(jù)庫索引在物理存儲層面可以分為兩類:聚集索引、非聚集索引猖闪。 1. 聚集索引(聚簇索引) 1...
    dragonMen閱讀 476評論 0 0
  • 一.索引簡介 眾所周知竖配,索引是關系型數(shù)據(jù)庫中給數(shù)據(jù)庫表中一列或多列的值排序后的存儲結構进胯,SQL的主流索引結構有B+...
    Binary_r閱讀 1,057評論 0 0
  • 1.索引簡介 眾所周知胁镐,索引是關系型數(shù)據(jù)庫中給數(shù)據(jù)庫表中一列或多列的值排序后的存儲結構盯漂,SQL的主流索引結構有B+...
    shoulda閱讀 988評論 0 1
  • Mysql數(shù)據(jù)庫索引按照物理實現(xiàn)方式分類就缆,索引可以分為 2 種:聚集索引和非聚集索引谒亦。 通常也把非聚集索引稱為二級...
    不屈真實閱讀 907評論 0 3
  • 1份招、聚集索引 聚集索引決定數(shù)據(jù)在物理磁盤上的物理排序锁摔,一個表只能有一個聚集索引,如果定義了主鍵孕豹,那么InnoDB會...
    鵝鵝鵝_閱讀 355評論 0 0