索引扫描而不是搜索

Posted

技术标签:

【中文标题】索引扫描而不是搜索【英文标题】:Index scan instead of a Seek 【发布时间】:2014-12-12 14:25:14 【问题描述】:

我在我的表上添加了一个新的计算列:

ALTER TABLE MyTable
ADD DATAORA_STOCK AS (Data_stock + Ora_Stock)

其中Data_Stock 类型为char(8)Ora_Stock 类型为char(6)

在此DATAORA_STOCK 列中创建新的非聚集 索引后:

CREATE NONCLUSTERED INDEX [IX_MyTable_DATAORA_STOCK] ON MyTable
(
    [DATAORA_STOCK] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

当我执行这两个查询时:

SELECT * FROM MyTable
WHERE DATAORA_STOCK = @Data1

还有:

SELECT * FROM MyTable
WHERE DATAORA_STOCK >= @Data1

我有两个不同的执行计划。首先查询在 IX_MyTable_DATAORA_STOCK 上查找,然后进行 Key Lookup。

为什么要第二次对聚集索引执行扫描索引?

OPTION(RECOMPILE) 运行良好,实际(未估计的)执行计划是正确的。 不幸的是,我无法修改查询文本,因为它是从应用程序调用的...... 我已经更新了我桌子上的统计数据,但没有任何变化。 确切的查询文本是:

SELECT * 
FROM MyView
WHERE DatAgg+OraAgg >= @Data1 AND DatAgg+OraAgg <= @Data2 

其中DatAgg+OraAgg是原始表中的DATAORA_STOCK(视图只是MyTable的投影),DATAORA_STOCK是计算列。

【问题讨论】:

可能是因为 >= 将获得很大比例的行。在 sql server 中是一个阈值,当条件获得超过 30% 的行时,优化器将切换到索引扫描而不是索引搜索。 @Mihai - 临界点远低于此。通常只有百分之几。 @MartinSmith 我的立场是正确的,有任何官方或非官方文档吗? @Mihai - 在此处查看 Kimberley Tripps 系列示例sqlskills.com/blogs/kimberly/the-tipping-point-query-answers 【参考方案1】:

因为索引没有覆盖,并且它估计由返回的行数

  WHERE DATAORA_STOCK >= @Data1

将导致大量查找以检索丢失的列值,因此仅扫描整个内容会更便宜。

如果估计错误,您可以尝试使用OPTION (RECOMPILE) 让它嗅探@Data1 的值(如果估计仍然错误,请更新该列的统计信息)

【讨论】:

以上是关于索引扫描而不是搜索的主要内容,如果未能解决你的问题,请参考以下文章

为啥这是索引扫描而不是索引查找

Spring JPA 查询始终使用序列扫描而不是索引扫描

文件排序而不是索引扫描

为啥当 WHERE 子句包含参数化值时 SQL Server 使用索引扫描而不是索引查找

如果我对非索引字段进行查询,是不是使用全表扫描

将索引扫描转换为索引查找