当从带有外部参数化“ where”子句的视图中调用时,窗口函数会导致糟糕的执行计划


10

很久以前,我遇到了这个问题,我找到了适合自己的解决方法,却忘了它。

但是现在在SO上存在这个问题,所以我愿意提出这个问题。

有一个视图以非常简单的方式(订单+订单行)连接了几个表。

当查询不带where子句的视图时,该视图将返回几百万行。
但是,没有人会这样称呼它。通常的查询是

select * from that_nasty_view where order_number = 123456;

这将返回5m中的10条记录。

重要的是:该视图包含一个窗口函数,该窗口函数rank()完全由始终查询该视图的字段划分:

rank() over (partition by order_number order by detail_line_number)

现在,如果使用查询字符串中的文字参数查询此视图(完全如上所示),它将立即返回行。执行计划很好:

  • 使用on的索引在两个表上进行索引查找order_number(返回10行)。
  • 在返回的微小结果上计算窗口。
  • 选择。

但是,当以参数化方式调用视图时,情况会变得很糟:

  • Index scan在所有表上忽略索引。返回5m行。
  • 巨大的加入。
  • 计算所有partitions上的窗口(约50万个窗口)。
  • Filter 从5m中取出10行。
  • 选择

在涉及参数的所有情况下都会发生这种情况。可以是SSMS:

declare @order_number int = 123456;
select * from that_nasty_view where order_number = @order_number;

它可以是ODBC客户端,例如Excel:

select * from that_nasty_view where order_number = ?

也可以是使用参数而不使用sql串联的任何其他客户端。

如果将窗口函数从视图中删除,则无论是否使用参数查询,它都能完美快速地运行。

我的解决方法是删除有问题的功能,然后在稍后阶段重新应用它。

但是,有什么用呢?这真的是SQL Server 2008如何处理窗口功能的错误吗?


order_number是主键?列和参数的数据类型是否匹配?
gbn 2012年

order_number不是主键。它是int not null用两个表中就可以了非聚集索引。
GSerg

5
SQL Server 2005 在这方面的谓词推送存在问题。我以为他们已经修复了。顺便说一句,您的TSQL示例使用变量而不是参数。添加OPTION (RECOMPILE)帮助吗?
马丁·史密斯

1
@GSerg-那么在过滤器的坏计划上,它最后有大约500万行进入过滤器,并且估计有10行与实际匹配?如果是这样,那么谓词推送问题仍然没有完全解决。
马丁·史密斯

Answers:


5

这似乎是一个长期存在的问题,它以一种或另一种形式重新铺装,并在SQL Server 2012中仍然存在。

一些讨论它的帖子是

直到(包括2012年)的所有当前版本的SQL Server都不能将分区组上的筛选器推过参数化谓词的序列项目的序列项目,除非option(recompile)已使用(如果使用2008+)。

recompile提示的替代方法是重写查询,以使用由@ a1ex07建议的参数化嵌入式TVF。


SQL Server 2014中也有这种情况
Guillaume86'6

3

我尝试用表值udf替换视图。这样,它将首先过滤记录,然后再应用窗口功能。此函数可以接受表参数,因此您可以将多个参数传递order_number给它


是另一种解决方法,是的。但我不能这样做,因为并非所有客户端都可以使用表值函数。
GSerg

为什么?我不确定100%,但是我想您所需要的只是将查询稍微更改为类似内容SELECT * FROM my_funct(12345)
a1ex07 '02

要求之一是该查询可由最终用户使用Excel(即通过MS Query)使用,并且MS Query不允许您这样做,至少在2003
之前的

it will filter records first, and then apply window function是不正确的。没有确定的执行顺序
Remus Rusanu 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.