3

对 SQL Server 的这种行为感到好奇。

正如我所期望的那样,此查询非常快速地产生结果:

SELECT *
FROM dbo.v_View1 View1 FULL OUTER JOIN
    dbo.v_View2 View2 ON View1.Portfolio = View2.Portfolio AND 
    View1.AsOfDate = View2.AsOfDate
where (View1.AsOfDate IN (NULL, '20130717'))

但是,我不想在那里有一个静态日期,所以我用子查询替换了它。不幸的是,我等待这个查询执行的最长时间是在我取消它之前 5 分钟,所以我不知道它是否真的会得到我想要的数据:

SELECT *
FROM dbo.v_View1 View1 FULL OUTER JOIN
     dbo.v_View2 View2 ON View1.Portfolio = View2.Portfolio AND 
     View1.AsOfDate = View2.AsOfDate
where (View1.AsOfDate IN (NULL, (SELECT MAX(AsOfDate) FROM dbo.v_View1)))

我已经诉诸于声明一个变量,使用上面的子查询设置它,并在 IN 语句中使用它,它按预期工作并且运行速度与原始查询一样快。

我知道我做错了什么或遗漏了什么(可能两者都有)——这是什么?我希望在 IN 语句中包含子查询,或者至少能够将其作为没有变量的视图运行。谢谢!

4

4 回答 4

4

我怀疑查询优化器正在做一些非常奇怪的事情,因为天真的实现涉及两次扫描,v_View1也许优化器没有意识到子查询SELECT MAX(AsOfDate) ...对于每一行都是相同的。我怀疑它可能没有意识到子查询与每一行都不相关,因此对结果集的每一行都运行它。考虑到完整的外部连接,大量数据意味着大量不必要的表扫描。

简单的解决方案是:

DECLARE @MaxAsOfDate datetime;
SET @MaxAsOfDate = (SELECT MAX(AsOfDate) FROM dbo.v_View1)

SELECT *
FROM dbo.v_View1 View1 FULL OUTER JOIN
    dbo.v_View2 View2 ON View1.Portfolio = View2.Portfolio AND 
    View1.AsOfDate = View2.AsOfDate
where (View1.AsOfDate IN (NULL, @MaxAsOfDate))

这将强制子查询运行一次,将结果存储在变量中,然后将其用于以下查询。

于 2013-07-19T18:07:35.313 回答
2

我相信它正在为它所对应的每条记录重新计算 MAX(AsOfDate) 。一个简单的解决方案是使用仅在开始时计算的 WITH 子句(也称为公用表表达式)。

于 2013-07-19T18:08:56.577 回答
1

我建议使用最上面的并更改它,使其在 IN 语句中没有 NULL 所以这样写

SELECT *
FROM dbo.v_View1 View1 FULL OUTER JOIN
    dbo.v_View2 View2 ON View1.Portfolio = View2.Portfolio AND 
    View1.AsOfDate = View2.AsOfDate
where View1.AsOfDate IN ('20130717') AND View1.AsOfDate IS NULL

还需要完全外连接吗?或者可以使用 INNER JOIN 吗?

此外,如果您查看执行计划并发布我将能够发布有关如何最好地优化此查询的更多信息,您还将看到查询花费时间最长的点

执行计划图片及展示方式

于 2013-07-19T18:13:08.027 回答
0

为了避免这个问题,重写它的一个简单方法是:

where View1.AsOfDate is null or View1.AsOfDate = (SELECT MAX(AsOfDate) FROM dbo.v_View1)

编辑:

您的问题在于查询运行多次。您的问题是视图高度未优化。您可以通过重新编译视图来解决此问题。将其编写为 SSMS中的ALTER语句并执行。自创建视图以来,基础表可能已更改。

我认为您也可以通过告诉 SQL Server 不要使用嵌套循环连接来解决此问题(这是导致性能问题的原因)。您可以通过添加option (hash join, merge join)到 SQL 语句的末尾来做到这一点。

于 2013-07-19T18:10:42.730 回答