导致聚簇索引扫描的日期参数
Date Parameter causing Clustered Index Scan
我有以下查询
DECLARE @StartDate DATE = '2017-09-22'
DECLARE @EndDate DATE = '2017-09-23'
SELECT a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
a.col3
FROM TableA a
JOIN TableB b
ON b.pred = a.pred
WHERE b.col2 > @StartDate AND b.col2 < @EndDate
当我运行检查实际执行计划时,我可以看到最昂贵的运算符是聚簇索引扫描(索引在a.pred)
但是,如果我按如下方式更改查询
SELECT a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
a.col3
FROM TableA a
JOIN TableB b
ON b.pred = a.pred
WHERE b.col2 > '2017-09-22' AND b.col2 < '2017-09-23'
取消索引扫描,使用索引查找。
有人可以解释这是为什么吗?在我看来,这与变量中的值可以是任何东西有关,因此 SQL 不知道如何计划执行。
有什么方法可以消除 table 扫描但仍然可以使用该变量? (PS,这将被转换为以@StartDate和@EndDate为参数的存储过程)
编辑
col2 是 DATETIME,但是,如果我将变量设置为 DATETIME,问题仍然存在
此查询有变量,此问题中有关 sql 服务器不知道您的变量值,因此必须根据结果集的猜测大小制定计划的建议与您的问题相关。
Why is SQL Server using index scan instead of index seek when WHERE clause contains parameterized values
但是,您提到要将此代码转换为存储过程。在将其转换为存储过程时,查询优化器应该能够嗅探变量的值并根据它们制定和执行计划。尝试将其转换为存储过程并执行它。在这些情况下,查询计划应该会有所改进。
SQL 使计划可重复用于变量。
当您使用变量时 - 它会在不知道您将传递的实际值的情况下编译查询。即使在这个 sql batch
中,值也是已知的。 但是它不需要为另一组传递参数重新编译查询。
因此,如果您对值进行硬编码 - DB 编译它会选择针对这些特定值优化的计划(例如,它会猜测通过日期检查的预期行数)。比使用变量要 'at least not worse'。但是 DB 需要为另一组硬编码值重新编译它(因为查询的文本已更改),这需要时间和垃圾 compiled query cache
存储取代其他有用的查询。
截至:
Is there any way I can eliminate the table scan but still have use of the variable? (PS, this will be converted to a stored procedure which takes @StartDate and @EndDate as parameters)
我认为 b.col2
上的非聚集索引可能是解决方案。该索引的键也可能包含 b.pred 作为代理键的一部分或包含 (with include(pred)
).
我有以下查询
DECLARE @StartDate DATE = '2017-09-22'
DECLARE @EndDate DATE = '2017-09-23'
SELECT a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
a.col3
FROM TableA a
JOIN TableB b
ON b.pred = a.pred
WHERE b.col2 > @StartDate AND b.col2 < @EndDate
当我运行检查实际执行计划时,我可以看到最昂贵的运算符是聚簇索引扫描(索引在a.pred)
但是,如果我按如下方式更改查询
SELECT a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
a.col3
FROM TableA a
JOIN TableB b
ON b.pred = a.pred
WHERE b.col2 > '2017-09-22' AND b.col2 < '2017-09-23'
取消索引扫描,使用索引查找。
有人可以解释这是为什么吗?在我看来,这与变量中的值可以是任何东西有关,因此 SQL 不知道如何计划执行。
有什么方法可以消除 table 扫描但仍然可以使用该变量? (PS,这将被转换为以@StartDate和@EndDate为参数的存储过程)
编辑
col2 是 DATETIME,但是,如果我将变量设置为 DATETIME,问题仍然存在
此查询有变量,此问题中有关 sql 服务器不知道您的变量值,因此必须根据结果集的猜测大小制定计划的建议与您的问题相关。
Why is SQL Server using index scan instead of index seek when WHERE clause contains parameterized values
但是,您提到要将此代码转换为存储过程。在将其转换为存储过程时,查询优化器应该能够嗅探变量的值并根据它们制定和执行计划。尝试将其转换为存储过程并执行它。在这些情况下,查询计划应该会有所改进。
SQL 使计划可重复用于变量。
当您使用变量时 - 它会在不知道您将传递的实际值的情况下编译查询。即使在这个 sql batch
中,值也是已知的。 但是它不需要为另一组传递参数重新编译查询。
因此,如果您对值进行硬编码 - DB 编译它会选择针对这些特定值优化的计划(例如,它会猜测通过日期检查的预期行数)。比使用变量要 'at least not worse'。但是 DB 需要为另一组硬编码值重新编译它(因为查询的文本已更改),这需要时间和垃圾 compiled query cache
存储取代其他有用的查询。
截至:
Is there any way I can eliminate the table scan but still have use of the variable? (PS, this will be converted to a stored procedure which takes @StartDate and @EndDate as parameters)
我认为 b.col2
上的非聚集索引可能是解决方案。该索引的键也可能包含 b.pred 作为代理键的一部分或包含 (with include(pred)
).