--- 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/)