SQL Server 基数估计警告

kyl*_*tme 3 sql-server cardinality-estimates

如何修复以下基数估计警告?

while exists(select 1 from @images)
begin
   declare @imageid     int
   declare @filename    varchar(max)
   select TOP (1)
      @imageid = [imageid],
      @filename = concat([imageid], '.', [extension])
   from
      @images
   order by
      [imageid]
   ...
   delete @images where [imageid] = @imageid
end
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

SQL Server 兼容级别:SQL Server 2019 (150)

J.D*_*.D. 6

有时,警告无非就是一个警告,而不是真正影响性能的东西。

最有可能影响您的性能的两件事是Table Variable,以及您正在循环而不是使用更相关的解决方案这一事实。所以我首先运行 aSELECT * INTO #images FROM @images将它放在循环之前的临时表中,然后在WHILE循环中使用该临时表,以潜在地提高性能。

要回答你的问题,不过,我相信事实,你imageid是一个INT但你在一个字符串函数使用它就像CONCAT()是在隐式转换是从即将被诱导的是基数估算警告。如果您将它的副本存储在已经转换为与字段类型相同的字符串数据类型并在函数中使用它的@images 表变量extension中,CONCAT()则警告应该消失。

此外,由于缺乏统计数据,表变量通常会导致基数估计不佳,这可能就是“每次执行的估计行数”显示为 1 的原因。(请注意SQL Server 2019 中的改进。)

  • 感谢 JD 我选择了一个表变量而不是临时表,因为数据集小于 20 条记录。我喜欢您在附加列中存储与字符串相同的值只是为了摆脱警告的想法。 (2认同)

Tib*_*szi 5

让我强调一下,这些类型的警告本质上是无用的,除非您真正深入查询并查看发生转换的位置。

下面会产生这样的警告,这完全是胡说八道。CAST 绝不会影响基数估计:

SELECT CAST(p.ProductID AS varchar(20))
FROM Production.Product AS p
Run Code Online (Sandbox Code Playgroud)

但是,以下警告是完全有效的:

SELECT *
FROM Production.Product AS p
WHERE CAST(p.ProductID AS varchar(20)) = 23
Run Code Online (Sandbox Code Playgroud)

请注意,为清楚起见,我在上面的示例中使用了显式 CAST。同样的原则也适用于隐式转换。