为什么在视图外部放置WHERE子句会产生糟糕的性能

时间:2011-07-11 17:28:19

标签: sql-server-2005 tsql where-clause sql-execution-plan

假设你有一个观点:

CREATE VIEW dbo.v_SomeJoinedTables AS
SELECT
    a.date,
    a.Col1,
    b.Col2,
    DENSE_RANK() 
      OVER(PARTITION BY a.date, a.Col2 ORDER BY a.Col3) as Something
FROM a JOIN b on a.date = b.date

我发现了以下的表现:

SELECT *
FROM v_SomeJoinedTables
WHERE date > '2011-01-01'

更糟糕
SELECT *, 
   DENSE_RANK() 
     OVER(PARTITION BY a.date, a.Col2 ORDER BY a.Col3) as Something
FROM a JOIN b ON a.date = b.date
WHERE a.date > '2011-01-01'

我很惊讶这两个语句的查询计划不一样。

我也尝试使用内联表值函数,但查询仍然比我复制和粘贴视图逻辑的代码长100-1000倍。

有什么想法吗?

5 个答案:

答案 0 :(得分:16)

它被称为“Predicate pushing”又称延迟过滤。

SQL Server并不总是能够有效地在视图内部“更早地”应用WHERE。

在SQL Server 2008中已经减轻了它,以便按预期工作更多

答案 1 :(得分:2)

我不是SQL专家,所以我可能因为我的愚蠢而被投票,但我的猜测是,在第一种情况下,SQL在应用谓词之前获取整个视图的结果在WHERE子句中。因此,当您查询视图时,它会选择所有记录,将它们放入内存中,然后在完成后应用Date过滤器。

这似乎类似于在WHERE中应用过滤器之前获取连接中指定的整个数据集的方式(这里的教训是您应该在可能的情况下在ON子句中应用谓词)。

除非以某种方式区别对待观点。

答案 2 :(得分:2)

OVER()语法在SS2005中是全新的,显然没有很好地集成到优化器中。我建议你试试更传统的表达方式吗?如果你关心可优化性,可能不是表达。

http://www.sqlteam.com/article/sql-sever-2005-using-over-with-aggregate-functions

或者,更好的是,对剖析器更加熟悉 - 视图应该是可以修复的。

答案 3 :(得分:1)

从技术上讲,您不是在相同的SQL语句之间进行比较。您的视图表明它返回a.date, a.Col1, b.Col2,加上您的DENSE_RANK()函数。在没有视图的查询中,您将返回所有列。

首先,您可能会认为返回所有列会更糟。但是如果不知道包括索引在内的表结构是什么样的话,很难确定哪个更好。

您是否比较了每个语句的查询计划?

答案 4 :(得分:-1)

作为一种解决方法,我建议使用函数而不是视图,以便传入数据参数。