11

我有一个插入选择语句,它只需要插入行的特定标识符在其他两个表中的任何一个中都不存在的行。以下哪个会更快?

INSERT INTO Table1 (...)
SELECT (...) FROM Table2 t2
WHERE ...
   AND NOT EXISTS (SELECT 'Y' from Table3 t3 where t2.SomeFK = t3.RefToSameFK)
   AND NOT EXISTS (SELECT 'Y' from Table4 t4 where t2.SomeFK = t4.RefToSameFK AND ...)

... 或者...

INSERT INTO Table1 (...)
SELECT (...) FROM Table2 t2
WHERE ...
   AND t2.SomeFK NOT IN (SELECT RefToSameFK from Table3)
   AND t2.SomeFK NOT IN (SELECT RefToSameFK from Table4 WHERE ...)

...或者他们的表现大致相同?此外,还有其他更好的方法来构造这个查询吗?我通常不喜欢子查询,因为它们为查询添加了另一个“维度”,通过多项式因子增加了运行时间。

4

4 回答 4

12

NOT IN通常是否比 慢/快并不重要,因为NOT EXISTS它们在. 读:NULL

不存在与不存在

在这些情况下,您几乎总是想要NOT EXISTS,因为它具有通常预期的行为。

如果它们是等效的,那么您的数据库很可能已经发现了这一点,并将为两者生成相同的执行计划。

在少数情况下,这两个选项是等效的并且您的数据库无法弄清楚,最好分析两个执行计划并为您的特定情况选择最佳选项。

于 2012-09-19T18:36:49.213 回答
1

您可以使用 LEFT OUTER JOIN 并检查 RIGHT 表中的值是否为 NULL。如果值为 NULL,则该行不存在。这是避免子查询的一种方法。

SELECT (...) FROM Table2 t2
LEFT OUTER JOIN t3 ON (t2.someFk = t3.ref)
WHERE t3.someField IS NULL
于 2012-09-19T18:27:43.923 回答
1

它取决于表的大小、可用的索引以及这些索引的基数。

如果您没有为两个查询获得相同的执行计划,并且如果两个查询都没有计划执行 JOIN 而不是子查询,那么我猜第二版更快。版本一是相关的,因此会产生更多的子查询,版本二可以满足总共三个查询。

(另外,请注意,不同的引擎可能会偏向一个方向或另一个方向。某些引擎可能会正确地确定查询是相同的(如果它们确实相同)并解析为相同的执行计划。)

于 2012-09-19T18:34:27.527 回答
0

对于较大的表,建议使用 NOT EXISTS/EXISTS,因为 IN 子句会根据表的体系结构多次运行子查询。

基于成本优化器:

没有区别。

于 2016-04-19T14:44:38.147 回答