为什么要执行表扫描?

Mik*_*ike 7 sql sql-server indexing

SELECT X.ID, X.Field4
FROM 
        #TaxInvoiceData T
INNER JOIN
        xxx X
        ON  T.Id = X.Id
        AND Field2 = @VAR     
        AND Field3 = 'S'
Run Code Online (Sandbox Code Playgroud)

当我在表X上运行查询全表扫描时.我不明白为什么因为表X的主键是

ID INT ASC
Field3 CHAR(2) ASC
Field2 DATETIME ASC  Unique Non-clustered
Run Code Online (Sandbox Code Playgroud)

还有一个索引

Field2 DATETIME ASC  Non-Unique Non-clustered
Run Code Online (Sandbox Code Playgroud)

做得好

SELECT ID
FROM xxx
WHERE 
    Field2 = @VAR   
AND Field3 = 'S'
Run Code Online (Sandbox Code Playgroud)

索引寻求

提前致谢.

zin*_*lon 5

简短的回答:因为优化器认为它会更快.

但是,让我们试着阅读优化器的想法.

由于您还没有提供完整的表模式,我将假设有一个聚簇索引xxx.ID,这#TaxInvoiceData是一个堆.您期望一个计划​​,其中PK索引被探测到每一行#TaxInvoiceData,但您正在选择xxx.Field4哪个需要为每个匹配查找书签.这可能导致29,000个随机I/O请求.哎哟.

相反,SQL Server可以(并且显然会)执行更大量的更高效的顺序I/O进行表扫描,并且可能正在进行快速的哈希匹配#TaxInvoiceData.

所以,你可以做什么?您可以创建覆盖索引,包括Field4.或者您可以使用索引和联接提示来强制您正在寻找的计划(但我怀疑性能不会像您希望的那样好).此查询是否经常使用,以至于它会给您的应用程序性能问题,或者您只是想在原则上消除表扫描?如果是后者,你可能会发现摆脱扫描的开销最终不值得.


编辑:

由于您已经提到表上没有聚集索引,这也可能会影响索引的查找效率.除非此表看到非常繁重的插入活动,否则请考虑将PK更改为群集.仅这一点可能会改变计划,即使它没有,也可能因为减少开销而加速其他操作.

  • 如果查询所需的所有内容都包含在索引中,SQL Server就可以查看并避免完全使用该表.这被称为查询的"覆盖索引",通常非常有效.情况并非如此,因为必须从表中读取Field4.问题在于,由于I/O开销,重复(数千次)查找索引行引用的表中的行不是非常有效.优化器在决定做什么时正在考虑所有这些. (5认同)