很久以前,我遇到了这个问题,我找到了适合自己的解决方法,却忘了它。
但是现在在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行。- 巨大的加入。
- 计算所有
partition
s上的窗口(约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-那么在过滤器的坏计划上,它最后有大约500万行进入过滤器,并且估计有10行与实际匹配?如果是这样,那么谓词推送问题仍然没有完全解决。
—
马丁·史密斯