在IN语句中挂起SQL Server的SELECT子查询

时间:2013-07-19 18:01:29

标签: sql sql-server

对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 个答案:

答案 0 :(得分: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))

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

答案 1 :(得分:2)

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

答案 2 :(得分: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吗?

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

Picture of execution plan and how to show it

答案 3 :(得分: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语句的末尾来执行此操作。