leafee98-blog/content/essays/sql-in-vs-join-exists.md

39 lines
1.8 KiB
Markdown
Raw Normal View History

---
title: "在 SQL 中使用 IN 或 JOIN 或 EXISTS"
date: 2021-04-25T17:57:31+08:00
tags: []
categories: []
weight: 50
show_comments: true
draft: false
---
IN 有一种特殊的情况为 semi-join (参考 2), 即当 IN 中子查询未使用外部表达式中的变量, 即子查询独立于外部查询, IN 中的子查询会单独执行并建立一个对于特定的列具有 UNIQUE 约束的临时的表, 随后对此表使用类似 JOIN 的操作, 对于原表的每一行都判断是否存在于此表中, 由于临时表具有 UNIQUE 约束(甚至可能建立索引), 从而使得每获得一行结果的复杂度降低到 n\*log 水平. 如果原表的对应列也具有索引, 那么甚至会到达 log\*log 的水平.
EXISTS 则是对于每一行进行子查询的运算, 某些情况下可能效率要高于简单的 JOIN, 某些情况下则会效率等同于 semi-join 的 IN 操作, 例如以下两个操作效率等同(参考 1)
```
select ...
from table_a
where col_1 in (
select col_1
from table_b
);
select ...
from table_a
where exists (
select 1
from table_b
where table_a.col_1 = table_b.col_1
)
```
结论: join 在无索引的表中表现较差, 原因是 semi-join 允许通过一个临时表进行聚合并复用此表进行匹配, 而 join 则有可能要通过两步(移除重复行和额外建立一个哈希表, 见参考 1, 此处涉及参考 1 中的测试语句然而由于本人懒惰尚未能在上面说明)来实现相同的操作.
**对于 semi-join 的直观解释建议直接阅读参考 2.**
## 参考资料:
1. [https://explainextended.com/2009/06/16/in-vs-join-vs-exists/](https://explainextended.com/2009/06/16/in-vs-join-vs-exists/)
2. [https://mariadb.com/kb/en/semi-join-materialization-strategy/](https://mariadb.com/kb/en/semi-join-materialization-strategy/)