【发布时间】:2013-03-16 02:39:06
【问题描述】:
我有以下 SQL:
IF EXISTS
(
SELECT
1
FROM
SomeTable T1
WHERE
SomeField = 1
AND SomeOtherField = 1
AND NOT EXISTS(SELECT 1 FROM SomeOtherTable T2 WHERE T2.KeyField = T1.KeyField)
)
RAISERROR ('Blech.', 16, 1)
SomeTable 表大约有 200,000 行,SomeOtherTable 表也差不多。
如果我执行内部 SQL(SELECT),它会在亚秒时间内执行,不会返回任何行。但是,如果我执行整个脚本 (IF...RAISERROR),则需要一个多小时。 为什么?
现在,显然,执行计划有所不同 - 我可以在 Enterprise Manager 中看到 - 但同样,为什么?
我可能会做一些类似SELECT @num = COUNT(*) WHERE ...然后IF @num > 0 RAISERROR 但是...我认为这有点忽略了这一点。如果您知道它存在,您只能围绕一个错误(而且它在我看来确实像一个错误)进行编码。
编辑:
我应该提一下,我已经尝试按照@Bohemian 的回答将查询重新插入到 OUTER JOIN 中,但这对执行时间没有影响。
编辑 2:
我附上了内部SELECT语句的查询计划:
...以及整个IF...RAISERROR块的查询计划:
显然,这些显示了真实的表/字段名称,但除此之外,查询完全如上所示。
【问题讨论】:
-
有趣的问题。你能提供给我们执行计划吗?
-
强制系统计算行数,而不是在确定any行存在后立即返回永远不要悲观——即使它确实改善了当前的性能问题,也只是一个意外,而不是解决根本问题。
-
运行查询需要多长时间:
select case when exists (SELECT 1 FROM SomeTable T1 WHERE SomeField = 1 AND SomeOtherField = 1 AND NOT EXISTS(SELECT 1 FROM SomeOtherTable T2 WHERE T2.KeyField = T1.KeyField) ) then 1 else 0 end? (通过使用case when exists,这应该使它能够短路而不是进行完整计数。) -
标签: sql sql-server