无法消除索引扫描

Rac*_*SQL 1 performance sql-server-2008 sql-server clustered-index query-performance

我有一个查询,即使使用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;
Run Code Online (Sandbox Code Playgroud)

这是我做的索引:

create index IX_CHAVEALEAT_CODCLIENTE
on tblcliente (chavealeat,codcliente)
include (chaveperiodo,codstatus,codstatusligacao)
Run Code Online (Sandbox Code Playgroud)

而且,这是分析:

覆盖索引

为什么显示计划index scan?我涵盖了所有栏目。我曾经option(recompile)更新计划。

这个指数有错吗?输出只有codcliente.

分析

我当时有 10-30 个查询在运行,并且没有 wait_info 问题。

Aar*_*and 5

仅仅因为您有一个覆盖索引并不意味着它不会扫描,也不意味着扫描仍然不是访问所请求数据的最佳方式。

你回来了,什么,300 万行?即使这不是表的大部分内容,执行 300 万次查找操作仍然没有多大意义,查找第一行并为其余行执行范围扫描也不可能有任何好处。还有一个问题是多个EXISTS子句——其中多个子句没有连接到索引的前导键列——不太可能都能够利用搜索的相同输出。并且您对所有INCLUDE列都有过滤器- 它们不是键的一部分,因此在这些列上查找将很困难(实际上,我见过的唯一一种情况是,当存在索引时仍然使用索引进行查找)WHERE针对非键列的子句是当列BIT,并且这些场景没有引入您上面的所有其他变量)。您也在使用PIVOT和聚合,我确定这无济于事。

另外,什么表CodCampo在(为什么它没有正确地以表别名作为前缀)?您可能有以下两个问题中的一个或两个:

  1. 这是一个分离(OR子句),可以阻止寻求(见保罗在这里的回答)。
  2. 如果它在 中tblcliente,那么您的索引无论如何都没有覆盖。

您可以尝试使用FORCESEEK提示运行查询(在 Paul 的示例中也提到过),它要么无法生成计划(不太可能),要么您将获得可以与我们共享的计划,如果您也共享扫描计划,您在没有提示的情况下,我们可以进一步了解 SQL Server 选择扫描的原因。

顺便说一句(这肯定不会帮助您进行搜索),因为估计值要低得多,我会检查您的统计数据是否是最新的。

最后,不要总是假设扫描是不好的,需要消除的东西!在很多情况下,扫描确实是检索数据的最佳方式。