神秘查询失败:为什么这会产生巨大的输出?

时间:2016-08-03 20:59:42

标签: sql sql-server-2012

我试图做一些基本的维恩图减法,将临时表与一些实时数据进行比较,看看它们是如何不同的。

这个查询在1500万个返回的行中爆炸了很多,我注意到它复制了(10,000x或更多)一个已知的唯一字段 - 表明我的查询出现了一些问题(我的意思是这个行是被复制,我可以通过这个全球唯一标识符字段验证这一点。我原本期望最多返回200行:

select a.*
    from TableOfLiveData a
        inner join #TempDataToBeSubtracted b
        on a.GUID <> b.guidTemp           --I suspect the issue is here   
    where {here was a limiting condition that should have reduced my live
           data to a "pre-join" count(*) of 20,000 at most...}

点击Execute之后,查询的运行时间比预期的要长得多,我可以看到在我必须取消之前已经返回了数百万行。

让我知道明显的是什么!?!?

编辑:仅供参考:如果没有包含where子句,我希望返回大量的行...

2 个答案:

答案 0 :(得分:1)

感谢@Lamak和@MartinSmith提出的解决此问题的意见。

使用&#39; not equals&#39;在我的&#34; on&#34;我确保我会选择LiveTable中我的#TempTable中没有GUID的每一行,而不是按照我的意图选择一次,但是对于我的#TempTable中的每个条目,我的结果乘以大约20,000这种情况(#TempTable的基数)。

为了解决这个问题,我在#TempTable上使用&#34; Not In&#34;做了一个简单的子查询。声明中建议的声明。这个查询在一分钟内完成,并返回100行,这更符合我的期望:

select a.*
    from TableOfLiveData a
    where a.GUID not in (select b.guidTemp from #TempDataToBeSubtracted b)
    and {subsequent constraint statement not relevant to question} 

答案 1 :(得分:1)

虽然您的查询逻辑正确,但问题是您的联接中有“笛卡尔积”(nxm行),但之后执行where子句加入了,所以你有一个庞大的行数,必须执行where子句...所以它会非常非常慢。

更好的方法是在键列上执行外部连接,但通过过滤错过的连接来放弃所有成功的连接:

select a.*
from TableOfLiveData a
left join #TempDataToBeSubtracted b on b.guidTemp = a.GUID
where a.field1 = 3
and a.field2 = 1515
and b.guidTemp is null -- only returns rows that *don't* match

这是有效的,因为当错过外部联接时,您仍然可以从主表中获取行,并且联接表中的所有列都是null

(field1, field2)上创建索引可以提高效果。