Sql 操作员使用tempdb溢出。。。。使用变量但不使用文本
需要了解此SQL Server行为的帮助吗 我有一个相当基本的问题,比如Sql 操作员使用tempdb溢出。。。。使用变量但不使用文本,sql,sql-server,Sql,Sql Server,需要了解此SQL Server行为的帮助吗 我有一个相当基本的问题,比如 select x, y, sum(z) from table where date between @start and @end group by x, y 有大量行(筛选条件检索1600万行中的600万行) 我不明白的是:这个查询很慢,我得到了一个关于溢出到tempdb的警告。但是如果我改变它,直接用相同的日期替换@start和@end,速度会快得多,而且不会出现tempdb溢出的警告 我的猜测是tempdb泄漏
select x, y, sum(z)
from table
where date between @start and @end
group by x, y
有大量行(筛选条件检索1600万行中的600万行)
我不明白的是:这个查询很慢,我得到了一个关于溢出到tempdb的警告。但是如果我改变它,直接用相同的日期替换@start
和@end
,速度会快得多,而且不会出现tempdb溢出的警告
我的猜测是tempdb泄漏是因为基数估计
似乎当我使用变量时,统计数据是不正确的。它估计大约有145万行,而不是600万行
当我使用文字时,估计几乎完全正确
在使用变量时,如何才能得到正确的估计值,并避免tempdb溢出?tempdb溢出是因为估计值,而估计值是不正确的,因为我使用的是局部变量 如果我用
sp_executesql
将局部变量更改为参数化SQL,估计值就正确了,tempdb溢出就消失了
然而,即使解决了tempdb溢出问题,参数化SQL仍然比使用文字慢,我为这个单独的问题创建了一个新问题
tempdb的泄漏是因为估计,但这是不正确的,因为 我用的是局部变量 一些关于他们为什么因为局部变量而出错的信息: SQL Server基数估计可以使用两种类型的统计信息来猜测通过谓词筛选器将获得多少行:
示例 案例1:Literal 我正在数据库上运行以下查询:
SELECT *
FROM Sales.SalesOrderDetail
WHERE UnitPriceDiscount = 0
我们有一个文本,因此CE将在单价折扣直方图中查找值0
,以计算将返回多少行
我有和,这是柱状图:
值0
是一个RANGE\u HI\u键,因此具有该值的估计行数是其EQ\u rows列-在本例中为117996.9
现在让我们看一下查询的执行计划:
“筛选”步骤将删除与谓词不匹配的所有行,因此其属性的“估计行数”部分具有基数估计的结果:
这是我们在直方图中看到的值,四舍五入
情况2:参数
现在,我们将尝试使用一个参数:
DECLARE @temp int = 0
SELECT *
FROM Sales.SalesOrderDetail
WHERE UnitPriceDiscount = @temp
基数估计器在直方图中没有要搜索的文字,因此它必须使用密度向量中列的总体密度:
这个号码是:
1 / the number of distinct values in the UnitPriceDiscount column
因此,如果将其乘以表中的行数,则得到该列中每个值的平均行数。Sales.SalesOrderDetail中有121317行,因此计算为:
121317 * 0.1111111 = 13479.6653187
执行计划:
过滤器的属性:
因此,新的估计来自密度向量,而不是直方图
如果您查看了stats对象,但它的总数与上面的不一样,请告诉我。您的统计数据是最新的吗?读得好:我认为基于看到正确的文字估计,统计数据是可以的。问题似乎是我的变量值没有被用于估算。如果您使用between vs.不等式运算符执行
where date>=@start and date相同的行为,会发生什么情况?因此,将其包装在sp_executesql中是您的解决方案?奇怪的是,不知道计划缓存是否在这里起了作用。我很好奇像Gordon Linoff这样的人会怎么说。谢谢。我不认为计划缓存是一个因素,因为我没有对任何其他值运行相同的查询。更可能的是,使用局部变量是“特殊的”-找到此链接