Sql-Server
無法消除索引掃描
我有一個查詢,即使使用 SQL Sentry,我也無法消除索引掃描。
這是查詢:
SELECT TOP 30 codCliente FROM ( SELECT t1.CodCliente, codcampo, valor, t1.chavealeat FROM tblCliente AS t1 WITH(NOLOCK) INNER JOIN tblClienteDetalhe AS t2 WITH(NOLOCK) ON t1.codcliente = t2.codcliente AND CodCampo IN(-1, 4) WHERE codStatus IN (0) AND t1.ChavePeriodo < GETDATE() AND t1.CodStatusLigacao = 0 AND EXISTS ( SELECT codcliente FROM tblclientedetalhe WITH(NOLOCK) WHERE codcampo = 3 AND valor = '2' AND codcliente = t1.codcliente ) AND EXISTS ( SELECT codcliente FROM tblclientedetalhe WITH(NOLOCK) WHERE codcampo = 6 AND CONVERT(DATETIME, Valor) BETWEEN '2015-08-01' AND '2015-08-31' AND DATEDIFF(DAY, Valor, GETDATE()) > 15 AND codcliente = t1.codcliente ) AND NOT EXISTS ( SELECT 0 FROM tblPesquisa WITH(NOLOCK) WHERE tblPesquisa.CodCliente = t1.CodCliente ) AND EXISTS ( SELECT codcliente FROM tblclientedetalhe WITH(NOLOCK) WHERE codcampo = 4 and valor = '202' and codcliente = t1.codcliente ) ) AS Cliente Pivot (MAX(Valor) FOR codCampo in ([4])) AS PivotTable WHERE (((([4] = '202')))) ORDER BY chavealeat;
這是我做的索引:
create index IX_CHAVEALEAT_CODCLIENTE on tblcliente (chavealeat,codcliente) include (chaveperiodo,codstatus,codstatusligacao)
而且,這是分析:
為什麼顯示計劃
index scan
?我涵蓋了所有專欄。我曾經option(recompile)
更新計劃。這個索引有錯嗎?輸出只有
codcliente
.當時我有 10-30 個查詢正在執行,並且沒有 wait_info 問題。
僅僅因為你有一個覆蓋索引並不意味著它不會掃描,也不意味著掃描仍然不是訪問請求數據的最佳方式。
你要返回,什麼,300 萬行?即使這不是表的大部分內容,執行 300 萬次查找操作仍然沒有多大意義,查找第一行並對其餘行執行範圍掃描也不可能有任何好處。還有一個問題是多個
EXISTS
子句——其中多個不連接到索引的前導鍵列——不可能都能夠利用查找的相同輸出。而且您在所有列上都有過濾器INCLUDE
-它們不是鍵的一部分,因此在這些列上查找將很困難(實際上,我看到索引仍然用於查找的唯一情況是WHERE
針對非鍵列的子句是該列是BIT
,並且這些場景並沒有引入您上面的所有其他變數)。你也在使用PIVOT
和聚合,我敢肯定這沒有幫助。另外,在什麼表
CodCampo
中(為什麼它沒有正確地以表別名作為前綴)?您可能會遇到以下兩個問題中的一個或兩個:
- 這是一個
OR
可以阻止尋求的析取(子句)(請參閱此處保羅的回答)。- 如果它在 中
tblcliente
,那麼您的索引無論如何都不會覆蓋。您可以嘗試使用
FORCESEEK
提示執行查詢(在 Paul 的範例中也提到過),它要麼無法生成計劃(不太可能),要麼您將獲得可以與我們共享的計劃,如果您還共享掃描計劃,您如果沒有提示,我們可以進一步了解 SQL Server 選擇掃描的原因。順便說一句(這肯定不會幫助你找到答案),因為估計值要低得多,我會檢查你的統計數據是否是最新的。
最後,不要總是認為掃描不好並且需要消除一些東西!在很多情況下,掃描確實是檢索數據的最佳方式。