1. 程式人生 > >和剛入門的菜鳥們聊聊--什麽是聚簇索引與非聚簇索引

和剛入門的菜鳥們聊聊--什麽是聚簇索引與非聚簇索引

condition 磁盤空間 大小 圖書館 uuid 存儲 成本 value row

今天我們來聊一聊關於 聚簇索引和非聚簇索引的問題;

  剛開始學數據庫SQL的時候,就知道有主鍵啊(Primary-key),外鍵啊(Foreign-key)啥的,連個表查詢就已經不清楚是要on 那幾個字段了,在數據量不太大的情況下,根本不會考慮索引的問題了,然後,隨著大數據時代的到來,數據量大了,沒有索引那是要不得的啊,客戶又吐槽了,你知不知道,你知不知道,我等到花兒都謝鳥。。。。。沒有索引,完全依賴生硬的where條件,達到百萬級數據記錄之後,如果沒有主鍵,頁面加載慢的一比,查詢頁面分分鐘可能被用戶直接關閉,剩下的你就等著 產品經理的一頓又一頓吐槽了吧。。。。。

OK,閑話不多扯了,言歸正傳,那我們來了解一下:

(一下僅供新人學習交流與個人體會,數據庫大神可直接無視,若有不當之處,歡迎大神雅正.)
- 什麽是索引;
- 什麽是聚簇索引和非聚簇索引;
- 為什麽要建索引;
- 動手試試,看看代碼怎麽敲的;
- 性能比較與分析;

什麽是索引.
我們來看看比較大眾的定義,OK,那就直接百度百科吧:"索引是對數據庫表中一列或多列的值進行排序的一種結構,使用索引可快速訪問數據庫表中的特定信息。" 看中心語-關鍵詞[一種結構],說到底索引就是對數據列的值進行結構化排序的一個東西.

通俗點講吧. 還記得大學軍訓的時候嗎,大夥第一天穿上迷彩服到運動場或者野外軍訓場地進行軍訓的時候,一般都是亂紮堆的吧,亂成一團,結果軍訓的教官來了,教官一看大夥,有男有女,有高有矮 幾分鐘很快就把大夥排成了m行n列的方針,盡然有序,高低有序;而且沒多久教官還能很快滴說出大家的名字,‘x行y列(或者xx號學員),王大錘,出列!’ 一聲令下,王大錘就從隊列中走出來了,...

這段場景中,教官就是軍訓場地上最好的【索引】;

什麽是聚簇索引和非聚簇索引
有了索引的概念認知,聚簇索引和非聚簇索引就好理解了,說一個最簡單的例子吧;

【聚簇索引】
平時習慣逛圖書館的童鞋可能比較清楚,如果你要去圖書館借一本書,最開始是去電腦裏面查書名然後根據書名來定位藏書在那個區,哪個書櫃,哪一行,第多少本。。。清晰明確,一目了然,因為藏書的結構與圖書室的位置,書架的順序,書本的擺放順序與書籍的編號都是從大到小一致的順序擺放的,所以很容易找到。比如,你的目標藏書在C區2櫃3排5倉,那麽你走到B區你就很快知道前面就快到了C區了,你直接奔著2櫃區就能找到了。 這就是雷同於聚簇索引的功效了,聚簇索引,實際存儲的循序結構與數據存儲的物理機構是一致的,所以通常來說物理順序結構只有一種,那麽一個表的聚簇索引也只能有一個,通常默認都是主鍵,設置了主鍵,系統默認就為你加上了聚簇索引,當然有人說我不想拿主鍵作為聚簇索引,我需要用其他字段作為索引,當然這也是可以的,這就需要你在設置主鍵之前自己手動的先添加上唯一的聚簇索引,然後再設置主鍵,這樣就木有問題啦。

總而言之,聚簇索引是順序結構與數據存儲物理結構一致的一種索引,並且一個表的聚簇索引只能有唯一的一條;

【非聚簇索引】
同樣的,如果你去的不是圖書館,而是某城市的商業性質的圖書城,那麽你想找的書就擺放比較隨意了,由於商業圖書城空間比較緊正,藏書通常按照藏書上架的先後順序來擺放的,所以如果查詢到某書籍放在C區2櫃3排5倉,但你可能要繞過F區,而不是A.B.C.D...連貫一致的,也可能同在C區的2櫃,書櫃上第一排是計算機類的書記,也可能最後一排就是醫學類書籍;

那麽對照著來看非聚簇索引的概念就比較好理解了,非聚簇索引記錄的物理順序與邏輯順序沒有必然的聯系,與數據的存儲物理結構沒有關系;一個表對應的非聚簇索引可以有多條,根據不同列的約束可以建立不同要求的非聚簇索引;

為什麽要建索引

這個問題肯定很簡單啦,看了上面的描述就知道了,肯定是為了加快找到目標數據的速度,節約查找話費的時間啦,用數據庫屬於來描述就是 :
建立索引的目的是加快對表中記錄的查找或排序。
但是話又說回來了,有了索引是不是就以為的數據的查詢快得不要不要的,。。。。
或者說,添加了索引之後,查詢速度一定回避沒有添加索引的情況下更快? 我看未必哦。。。
我們還是先了解一下 家裏索引需要付出的代價和帶來的弊端吧:
一.增加了數據庫的存儲空間,
二.在插入和修改數據時要花費較多的時間(因為索引也要隨之變動);

我們假設在一張表中的一條記錄在磁盤上占用1KB話,我們對其中10B的一個字段建立索引,那麽該記錄對應的索引塊的大小只有10B,如果一張表的的數據量比較大,大約100,000條,那麽用來存儲索引耗費的空間就是100,000X10B=1000,000B=10000KB=1MB,換句話說,這張白表也因為這個索引的建立而多使用了大約1MB的存儲空間,當然對與大批量數據來說,這麽點空間是不足為道的。但事實是,索引確實耗費了更多空間;

關於第二條我就不用贅述了,這個文字描述已經說的很清楚;
還有就是,對某些場景下,數據量不是特別大的情況下,對於某些添加索引的行為,不但不能優化查詢速度,反而會減慢查詢速度,當然,如果索引的建立不恰當,所選擇建立索引的字段不合適,也可能會削弱查詢速度,當然在數據量不大的情況下,基於SQL服務器本身強大的處理能力,這種削弱表現是非常微弱的,但是一旦數據量大起來,原本可以不需要考慮索引就能很快查詢出來數據的,結果因為添加了索引反而加重了查詢數據的消耗,不恰當的索引方式造成的影響就會表現的很明顯;
所以,索引不是萬能的,某些情況下,添加索引可能比不添加索引更慢!

動手試試:看看代碼怎麽敲的

建立索引之前選好表對象,假設表明為IndexTestTable此表中包含三個字段Id,Name,UniqueCode
為了更快的進行姓名查詢,我們可以在Name字段上添加非聚簇索引;
創建索引的格式如下:
CREATE NONCLUSTERED INDEX [index_name【索引名稱】] ON [table_name【表名稱】]([column_name1【列名稱】],[column_name2【列名稱】],...);
我們給IndexTestTable表的Name字段添加一個非聚簇索引:
CREATE NONCLUSTERED INDEX IndexTestTable_index_name ON IndexTestTable(Name);
給IndexTestTable表的UniqueCode字段添加一個聚簇索引:
CREATE CLUSTERED INDEX IndexTestTable_index_uniquecode ON IndexTestTable(UniqueCode)
以上的代碼是最簡單最直接設置索引的方式,而通常實際應用中,會有多字段聯合添加索引的情況,這個就需要你根據實際的應用查詢場景,以及在where條件下最常用的查詢字段,例如:在 TableX中你最經常查詢的條件為:
SELECT Name,Message FROM TableX
WHERE 1=1 AND DeptId=‘003523‘
AND LimitedCondition=‘SomeValue‘
這個時候你就可以 添加一個基於 DeptId 和 LimitedCondition 兩個字段的非聚簇索引,以便於加速查詢速度;
CREATE NONCLUSTERED INDEX TableX_index_departid_limitedcondition ON TableX(DeptId,LimitedCondition);
簡言之,就是需要根據你的實際應用場景,添加有用並且高效的索引;

性能比較與分析;
在一個有千萬級數據量的某表mytable中(表沒有實際意義用途,僅限於數據查詢研究,只用三個字段),查詢數據總數,遍歷表記錄耗時大約15秒;
SELECT COUNT(id) FROM mytable;
/* Affected rows: 0 已找到記錄: 1 警告: 0 持續時間 1 query: 14.750 sec. */
查詢某一行數據,基於主鍵Id查詢,耗時1秒不到;
SELECT * FROM mytable WHERE id = 7351158;
/* Affected rows: 0 已找到記錄: 1 警告: 0 持續時間 1 query: 0.031 sec. */

但是同樣是上面 一行數據 如果查詢UUID這個種字符型數據且未設置索引的情況下,則需要耗時較長時間;
SELECT * FROM mytable WHERE xuuid = ‘0e670e7a-427e-11e6-beb1-286ed48926ad‘;
/* Affected rows: 0 已找到記錄: 1 警告: 0 持續時間 1 query: 15.563 sec. */

現在我們在 xuuid上添加一條索引;
CREATE NONCLUSTERED INDEX mytable_index_xuuid ON mytable(xuuid);
好吧 接下來見證奇跡的時候到了,我們一起來看一下,加完索引之後有什麽神奇的變化:
SELECT * FROM mytable WHERE xuuid = ‘0e670e7a-427e-11e6-beb1-286ed48926ad‘;
/* Affected rows: 0 已找到記錄: 1 警告: 0 持續時間 1 query: 0.046 sec. */
看清楚了, 是0.046秒,換句話說,是46毫秒;
這樣來說,數據查詢優化的空間可是相當大有可為的,童鞋們學好索引的正確打開方式,對以後加快查詢方式會有很大的幫助哦....

最後引用別人[姜敏(http://www.cnblogs.com/aspnet2008/)]曾經總結過的幾句話來描述一下索引的使用原則:
總結索引使用原則:
1:不要索引數據量不大的表,對於小表來講,表掃描的成本並不高。
2:不要設置過多的索引,在沒有聚集索引的表中,最大可以設置249個非聚集索引,過多的索引首先會帶來更大的磁盤空間,而且在數據發生修改時,對索引的維護是特別消耗性能的。
3:合理應用復合索引,有某些情況下可以考慮創建包含所有輸出列的覆蓋索引。
4:對經常使用範圍查詢的字段,可能考慮聚集索引。
5:避免對不常用的列,邏輯性列,大字段列創建索引。

和剛入門的菜鳥們聊聊--什麽是聚簇索引與非聚簇索引