用“where”调用的视图中的窗口函数给出了错误的执行计划

时间:2016-04-01 08:56:45

标签: sql sql-server

我有一个使用LAG的视图。

CREATE VIEW V_ImportedReadingDay2
AS
SELECT
    ID,
    PlacementID,
    LAG(Reading, 1) OVER (PARTITION BY MeterNumber ORDER BY Date) AS Val
FROM dbo.ImportedReadingDay

如果我使用“WHERE”调用它,那么执行计划会比调用查询时更糟糕。

SELECT
    ID,
    PlacementID,
    LAG(Reading, 1) OVER (PARTITION BY MeterNumber ORDER BY Date) AS Val
FROM dbo.ImportedReadingDay
WHERE (PlacementID = 12404)

SELECT *
FROM V_ImportedReadingDay2
WHERE (PlacementID = 12404)

enter image description here

这是一个已知问题。你可以谷歌问题。 我找到了两个解决方案。使用表值函数或将LAG移动到视图之外。

但我想知道是否有其他解决方案,因为我不得不在客户端软件中使用该视图,因为这些都不适合我。

2 个答案:

答案 0 :(得分:3)

您的两个查询在逻辑上并不相同。所以,当然,他们没有得到相同的执行计划。

考虑以下问题:

select name,LAG(column_id) OVER (ORDER BY system_type_id) as cid
from sys.columns
where name='name'

select * from (
select name,LAG(column_id) OVER (ORDER BY system_type_id) as cid
from sys.columns
) t
where name='name'

由于查询的逻辑处理顺序,WHERE子句在SELECT子句之前处理。因此,对于第一个查询,我们首先过滤sys.columns表以仅检索具有特定名称的行,然后然后我们应用LAG()仅对此过滤集合起作用(因此,滞后值肯定来自与过滤器匹配的另一行)。

对于第二个查询,我们首先(逻辑上)处理子查询。我们在整个行集中执行LAG()函数(因为子查询没有任何过滤器/ WHERE子句)然后(在外部查询中)我们正在过滤行。重要的是,这意味着滞后值可能是从与最终过滤器不匹配的行中拉出来的。

好吧,当你使用一个视图时,它与我的第二个查询类似。使用视图时检索到的Val not 保证来自PlacementID等于12404的行。

答案 1 :(得分:1)

这是本例的简化视图。 在真正的我分区LAG。 我发现用“WHERE”(在本例中为PlacementID)中使用的LAG进行分区解决了性能问题。