当使用between运算符和硬编码参数值从表中进行选择时,我得到一个正确的查询计划,其中3个估计行与2个实际行相比:
select v.Date from Dates v
where v.Date between '20130128' and '20130129';
但是,当使用参数替换硬编码值时,查询计划会更改为非常糟糕的计划,估计行数超过6000,实际行数仅为2行:
select v.Date from Dates v
where v.Date between @startdate and @enddate;
查询计划本身是相同的,只是估计行的差异导致参数化查询比硬编码查询慢大约4倍.有什么我不知道为什么参数化版本运行得那么慢,我可以给SQL Server什么索引/提示,以帮助它使用正确的查询计划?
一些额外的信息:
>使用简单的等于=标准时不会出现问题,它似乎特定于运算符之间.
>如果我在参数化查询的末尾添加选项(重新编译),我会得到一个完美的查询计划,与硬编码查询相同.
>日期表只有两列,Date和DateID,主键DateID列上有聚簇索引,Date列上有唯一的非聚簇索引.都有更新的统计数据.
>查询计划为硬编码查询执行自动参数化,将硬编码值替换为@ 1和@2,并将查询显示为大写.它似乎不会对参数化查询执行任何转换.
>使用SQL Server 2008 R2.
我知道足够让人怀疑这是某种参数嗅探问题.为什么不在查询中添加选项(重新编译)?这被用作更大的复杂查询的一部分,我理解良好的做法是让SQL Server尽可能地从缓存中重用查询计划.
编辑和更新:感谢目前为止的深思熟虑的回应.为了进一步细化问题,查询计划为上述两个查询使用了一个非常好的索引,但为什么它不能识别参数化查询的日期范围只有两天宽,为什么它认为范围是6000行宽?特别是当查看查询计划时,SQL Server正在为硬编码查询执行自动参数化?在基础查询计划中,两个计划看起来都相同,因为它们都是参数化的!
查询计划基于SQL查询的哈希进行缓存.因此,对于两个版本的查询,都有一个不同的缓存槽.
添加选项(重新编译)是一个很好的解决方案.你也可以使用:
option (optimize for (@startdate = '20130128', @enddate = '20130129'));
生成查询计划,就像传入了这些值一样.
要进行测试,您可以使用以下命令从缓存中删除所有计划:
DBCC FREEPROCCACHE
相关文章
- sql-server - 此查询如何在执行计划中生成两个连接运算符?
- c# - 使用实体框架的SQL查询运行速度较慢,使用错误的查询计划
- sql-server - 使用参数化SQL时,SQL Server使用相同的查询缓存查询计划
- sql-server - 为什么参数化查询产生的查询计划与非参数化查询大大减慢
- sql-server - 查询计划中的运算符成本高得多的指示?
- sql - 查询查询运行时错误.无法在非数字类型上应用二进制数字运算符[* | /]
- sql-server - 执行计划有TOP运算符,用于查询而不使用TOP或ORDER BY
- sql-server - 由于此查询中定义的提示,查询处理器无法生成查询计划.重新提交查询,而不使用SET FORCEPLAN
转载注明原文:sql – “Between”运算符在使用参数时生成错误的查询计划 - 代码日志