--============================================
領導指點我去給某台數據庫調優下,結果屁顛屁顛地干完,還自我感覺良好,剛剛別人博客時,才發現自己踩坑了!!
--============================================
有一很簡單查詢SQL,類似:
SELECT * FROM TB1 WHERE C1='C1' AND C2='C2' AND C3='C3' AND C4='C4'
發現該SQL執行很慢,一看是全表掃描,便考慮WHERE條件中每列的可選擇行,表中有700W數據
查看C1的可選擇性
SELECT COUNT(DISTINCT C1) FROM TB1 WITH(NOLOCK)
發現C1列去重后有140W,選擇性比較高,優先作為索引的第一個鍵值列。
SELECT TOP(100) C1,COUNT(1) AS Rcount FROM TB1 GROUP BY C1 ORDER BY Rcount
結果發現C1列中值為"無效"的行有幾十萬條,其余值最多也才300多條。這就讓我糾結了,數據分布不均勻,很容易導致參數嗅探的問題,趕快訊詢問開發,確認是否會使用“無效”來查詢,得到明確答復不會使用(無用的數據沒有刪除而修改值為無效,好霸氣的做法),於是乎,過濾索引瞬間冒出來
CREATE INDEX IDX_TB1_C1 ON TB1(C1) WHERE C1<>'無效' WITH(MAXDOP=6)
多么完美的解決方案啊,自我感覺良好中。。。
-------------------------------------------------------------------------------
過了兩小時,加查索引使用情況
SELECT * FROM sys.dm_db_index_usage_stats WHERE database_id = DB_ID() AND object_id=OBJECT_ID('TB1')
發現索引完全沒有被使用,不可能啊,再次檢查SQL腳本
(@P0 NVARCHAR,@P1 int,@P2 int,@P3 int) SELECT * FROM TB1 WHERE C1=@P0 AND C2=@P1 AND C3=@P2 AND C4=@P3
以我多年的經驗,我武斷地判斷隱式轉換導致,因為這問題出現不是一次兩次啦,C1列時VARCHAR類型的,於是乎,通知開發改程序,收工!!
--==================================================================================
真的收工了嗎?當然沒有,要不然我還啰嗦啥呢
在Amaranthus的大作中有這樣一句話:
在沒有recompile提示之下,過濾索引和過濾統計信息不會被應用到參數化的字段過濾。(In the absence of a RECOMPILE hint, filtered indexes and statistics will not be used in conjunction with parameterization that refers to the filter column.)
對於參數化的過濾條件,查詢優化器無法確認未來傳入的具體值滿足過濾索引中的過濾條件,因此不會考慮使用過濾索引
解決辦法:
1. 將索引過濾條件移除(由於查詢不會使用“無效”,因此不會出現參數嗅探問題)
2. 在查詢條件中顯示加入過濾條件(SQL 中加入 AND C1<>'無效',有點畫色添足的感覺)
吭只有踩過才知道啊!!!
--====================================================================================
妹子