当使用窗口函数并且谓词包含变量时,SQL Server使用scan而不是seek

时间:2012-10-19 14:33:51

标签: sql sql-server performance

看看这个小提琴:http://sqlfiddle.com/#!6/18324/2

展开第一个执行计划,针对查看B的查询 请注意,第一个查询使用索引搜索执行,而第二个查询使用索引扫描执行。在我的实际设置中,有数千行,这会产生非常可观的性能损失。

WTF ???

查询是等价的,不是吗?为什么文字产品寻求和变量扫描?
但更重要的是:我该如何解决这个问题

This post最接近问题,从那里起作用的解决方案是使用option(recompile)(谢谢你,Martin Smith)。但是,这对我不起作用,因为我的查询是由我的ORM库(实体框架)生成的,我不能手动修改它们。
而我正在寻找的是一种重新构造B视图的方法,以便不会出现问题。

在摆弄这个问题时,我注意到执行计划中的“Segment”块总是丢失谓词。为了验证这一点,我根据具有min函数的子查询重新构造了查询(请参阅视图D)。瞧! - 针对D视图的两个查询都会产生相同的计划。

然而,坏消息是我无法使用此min提供的技巧,因为在我的实际设置中,列Y实际上是几列,所以我可以通过他们订购,但我不能拿min()他们 所以第二个问题是:任何人都可以提出类似于min-powered子查询的技巧,但适用于多个列?

注意1 :这与引爆点无关,因为表格中只有2条记录。
注意2 :它也与视图的存在无关。查看视图C的示例:在这种情况下,服务器很乐意使用搜索。

3 个答案:

答案 0 :(得分:0)

可能这个会起作用

select a.X, a.Y from A a
    cross apply
        (select top 1 * from A t where t.X = a.X order by t.Y asc) as idx

SQLFiddle http://sqlfiddle.com/#!6/a3362/2

答案 1 :(得分:0)

查询会产生等效输出,但是in the eyes of the sql optimizer they are different.文章建议查看OPTION clause (unfortunately not included before SQL 2005).

你可以Brew Your Own Query on top of the Entity Framework,这可能是达到理想表现的最佳选择。

答案 2 :(得分:0)

这是我自己的答案。

最终,我使用了min驱动的技巧,我通过将这些列转换为恒定长度的字符串表示(仔细调整以进行排序)来解决Y实际上是几列的事实。将这些字符串连接成一个字符串。完成后,我可以使用该连接的字符串作为min()的参数。

我仍然想知道这样做的正确方法。如果有人碰巧知道它,我会很感激。