我很好奇EXISTS()
的执行应该如何比IN()
更快。
EXISTS()
时,它使用相关子查询(从属子查询),而IN()仅使用子查询。
EXPLAIN显示EXISTS
和NOT EXISTS
都使用从属子查询,而IN / NOT IN
都只使用子查询..所以我很好奇相关子查询如何比子查询更快? ?
之前我使用过EXISTS并且执行速度比IN快,这就是为什么我感到困惑。
以下是SQLFIDDLE及解释
EXPLAIN SELECT COUNT(t1.table1_id)
FROM table1 t1
WHERE EXISTS
( SELECT 1
FROM table2 t2
WHERE t2.table1_id <=> t1.table1_id
);
+-------+-----------------------+-----------+-------+---------------+-----------+--------+--------------------------+--------+------------------------------+
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY |KEY_LEN | REF | ROWS | EXTRA |
+-------+-----------------------+-----------+-------+---------------+-----------+--------+--------------------------+--------+------------------------------+
| 1 | PRIMARY | t1 | index | (null) | PRIMARY | 4 | (null) | 4 | Using where; Using index |
| 2 | DEPENDENT SUBQUERY | t2 | REF | table1_id | table1_id| 4 | db_9_15987.t1.table1_id | 1 | Using where; Using index |
+-------+-----------------------+-----------+-------+---------------+-----------+--------+--------------------------+--------+------------------------------+
EXPLAIN SELECT COUNT(t1.table1_id)
FROM table1 t1
WHERE NOT EXISTS
( SELECT 1
FROM table2 t2
WHERE t2.table1_id = t1.table1_id
);
+-------+-----------------------+-----------+-------+---------------+-----------+--------+--------------------------+--------+------------------------------+
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY |KEY_LEN | REF | ROWS | EXTRA |
+-------+-----------------------+-----------+-------+---------------+-----------+--------+--------------------------+--------+------------------------------+
| 1 | PRIMARY | t1 | index | (null) | PRIMARY | 4 | (null) | 4 | Using where; Using index |
| 2 | DEPENDENT SUBQUERY | t2 | ref | table1_id | table1_id| 4 | db_9_15987.t1.table1_id | 1 | Using index |
+-------+-----------------------+-----------+-------+---------------+-----------+--------+--------------------------+--------+------------------------------+
EXPLAIN SELECT COUNT(t1.table1_id)
FROM table1 t1
WHERE t1.table1_id NOT IN
( SELECT t2.table1_id
FROM table2 t2
);
+-------+-------------------+-----------+-------+---------------+-----------+--------+----------+--------+------------------------------+
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY |KEY_LEN | REF | ROWS | EXTRA |
+-------+-------------------+-----------+-------+---------------+-----------+--------+----------+--------+------------------------------+
| 1 | PRIMARY | t1 | index | (null) | PRIMARY | 4 | (null) | 4 | Using where; Using index |
| 2 | SUBQUERY | t2 | index | (null) | table1_id| 4 | (null) | 2 | Using index |
+-------+-------------------+-----------+-------+---------------+-----------+--------+----------+--------+------------------------------+
FEW问题
在上面的解释中,EXISTS如何在额外内容中using where
和using index
但是EXESTS在附加内容中没有using where
?
相关子查询如何比子查询更快?
答案 0 :(得分:9)
这是与RDBMS无关的答案,但可能会有所帮助。在我的理解中,相关(又名,依赖)子查询可能是最常被误导的错误表现的罪魁祸首。
问题(最常见的描述)是它处理外部查询的每一行的内部查询。因此,如果外部查询返回1,000行,并且内部查询返回10,000,那么您的查询必须通过10,000,000行(外部×内部)来产生结果。与来自相同结果集的非相关查询的11,000行(外部+内部)相比,这是不好的。
然而,这只是最糟糕的情况。在许多情况下,DBMS将能够利用索引来大幅减少行数。即使只有内部查询可以使用索引,10,000行也会变成~13次搜索,这会使总数下降到13,000。
exists
运算符可以在第一个之后停止处理行,从而进一步降低查询成本,尤其是当大多数外行与至少一个内行匹配时。
在极少数情况下,我看到SQL Server 2008R2优化了相关子查询到合并连接(它只遍历两个集合 - 最好的情况),在内部和外部查询中都可以找到合适的索引。
性能不佳的真正原因不一定是相关子查询,而是嵌套扫描。
答案 1 :(得分:3)
这取决于MySQL版本 - MySQL查询优化器中存在一个错误,版本高达6.0。
“IN”的子查询没有正确优化(但是一次又一次地执行,就像从属的那样)。此错误不会影响exists
查询或加入。
问题在于,对于使用IN子查询的语句, 优化器将其重写为相关子查询。考虑以下 使用不相关子查询的语句:
SELECT ... FROM t1 WHERE t1.a IN(SELECT b FROM t2);
优化器将语句重写为相关子查询:
SELECT ... FROM t1 WHERE EXISTS(SELECT 1 FROM t2 WHERE t2.b = t1.a);
如果内部和外部查询分别返回M和N行 执行时间变为O(M×N),而不是O(M + N) 这将是一个不相关的子查询。
参考文献
答案 2 :(得分:1)
如您所知,子查询不使用外部查询中的值,因此它只执行一次。相关子查询是同步的,因此它对外部查询中处理的每一行执行。
使用EXISTS
的优点是,如果认为满足,则在返回至少一行后,子查询的执行会停止。因此,它可以比简单的子查询更快。但这不是一般规则!所有这些都取决于您正在执行的查询,查询优化器和SQL执行引擎版本。
EXISTS
条件语句时使用 if
,因为它肯定比count
更快。
您无法使用简单的4或3个查询基准比较两个子查询。
希望它有用!