測試表結構:
CREATE TABLE TB1( ID INT IDENTITY(1,1), C1 INT, C2 INT)
1. 聚集索引(Clustered index)
聚集索引可以理解為一個包含表中除索引鍵外多有剩余列的包含索引,為保證在DELETE/UPDATE操作的正確性,如果聚集索引未聲明為唯一(UNIQUE),則系統會聚集索引鍵增加一個NULLABLE的INT類型標識列(UNIQUIFIER)以保證記錄唯一性。
唯一聚集索引:
CREATE UNIQUE CLUSTERED INDEX IDX_IDON TB1( ID)
非唯一聚集索引:
CREATE CLUSTERED INDEX IDX_IDON TB1( ID)
2. 非唯一非聚集索引
為從非聚集索引定位到數據,對于堆表,非聚集索引會存放索引鍵+數據的RID(FILE_ID+PAGE_ID+SLOT_ID),對于聚集表,非聚集索引會存放索引鍵+聚集索引鍵。
非聚集索引:
CREATE INDEX IDX_C1ON TB1( C1)
堆表上非聚集索引:
唯一聚集索引表上非聚集索引:
非唯一聚集索引表非聚集索引:
--==============================
后續的測試默認使用唯一聚集索引
--==============================
3. 唯一非聚集索引
唯一非聚集索引與非唯一非聚集索引的區別主要在非葉子節點上,唯一非聚集索引的非葉子節點上不會包含RID的數據。
唯一非聚集索引:
CREATE UNIQUE INDEX IDX_C1_UNION TB1( C1)
4. 包含索引
包含索引在SQL SERVER 2008版本中引入,包含列的數據只存在在葉子節點上。包含列不影響索引行的位置(不會被排序),且包含列不會影響索引鍵的大小(SQL SERVER 限制索引鍵不得超過900字節)
CREATE INDEX IDX_C1_INC_C2ON TB1( C1)INCLUDE( C2)
5. 過濾索引
當過濾列不作為索引鍵或包含列時,系統無需在索引中存放過濾列的數據,因此過濾列不會出現在索引的葉子節點和非葉子節點上。
CREATE INDEX IDX_C1_WH_C2ON TB1( C1)WHERE C2>1
--=============================================================
總結&建議:
1. 對于聚集表,由于索引非聚集索引都會包含聚集鍵,因此建議優先考慮靜態+唯一+遞增+長度較小的索引鍵作為索引鍵
a. 靜態:當聚集鍵被更新時,除了將表數據移動到相應的位置上,依次更新所有的非聚集索引,會消耗大量資源,并導致頁拆分和索引碎片
b. 唯一: 非唯一聚集索引增加2至6個字節的消耗,導致聚集索引和非聚集索引消耗更多頁面
c.遞增:對于非遞增的聚集索引鍵來說,插入操作會引發頁拆分和索引碎片
d. 長度較小:長度較大的聚集索引鍵同樣會導致聚集索引和非聚集索引消耗更多頁面,尤其是導致索引層數增加,增加INDEX SEEK的開銷。
2. 索引列的可選擇性和索引列順:高選擇性不代表該列就適合放在索引前部,還應該考慮針對該列是范圍查詢還是等值查詢,如訂單表的創建時間列CreatedTime主要用作范圍查詢,而訂單表的產品編號PRoductID主要用等值查詢,那么對于
WHERE ProductID=@P1 AND CreatedTime>@P2AND CreatedTime<@p3
這樣的查詢,索引 INDEX(ProductID,CreatedTime)就會比INDEX(CreatedTime,ProductID) 更高效(消耗更少的CPU和IO資源)。
3. 索引列順序與統計:索引列先后順序不同,其對于的統計信息的密度(density)和直方圖(histogram)也不相同,會間接影響到生成的執行計劃。
4. 對于選擇性較低且位于索引列后端的列來說,可以考慮將其放入到包含索引列中。
5. 雖然過濾索引在統計信息更新方面存在一定的問題,過濾索引依然是解決部分疑難雜癥的必殺技(如SELECT TOP(10) * FROM orders WHERE ProductID>10000 ORDER BY OrderID DESC)
6. 在對遞增的列建立索引時,應考慮統計過期導致執行計劃低效的問題,如對訂單表上創建日期列建立索引。
--==========================================================
寫得不好,靠妹子加分啦。。
新聞熱點
疑難解答