我有一个insert-select语句,只需插入行中特定标识符不存在于其他两个表中的行。以下哪项会更快?
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 ...)
......或者他们的表现差不多吗?另外,有没有其他方法来构建这个查询更好?我通常不喜欢子查询,因为它们为查询添加了另一个“维度”,通过多项式因子增加运行时间。
答案 0 :(得分:10)
通常NOT IN
比NOT EXISTS
更慢/更快并不重要,因为它们在NULL
存在时 NOT 等效。读:
在这些情况下,您几乎总是想要NOT EXISTS
,因为它通常具有预期的行为。
如果它们是等价的,那么您的数据库可能已经计算出来并且将为两者生成相同的执行计划。
在少数情况下,两个选项都具有竞争性,而您的数据库无法解决这个问题,最好分析两个执行计划并为您的特定情况选择最佳选项。
答案 1 :(得分: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
答案 2 :(得分:1)
它取决于表的大小,可用的索引以及这些索引的基数。
如果你没有为两个查询获得相同的执行计划,并且如果两个查询都没有计划执行JOIN而不是子查询,那么我猜第二版更快。版本1是相关的,因此会产生更多的子查询,第二版可以满足三个查询总数。
(另外,请注意,不同的引擎可能会偏向一个方向或另一个方向。某些引擎可能正确地确定查询是相同的(如果它们确实 相同)并解析为相同执行计划。)
答案 3 :(得分:0)
对于较大的表,建议使用NOT EXISTS / EXISTS,因为IN子句根据表的体系结构运行子查询很多次。
基于成本优化器:
没有区别。