编程SQL开发者

解释 SQL 中 EXISTS 和 IN 运算符的工作特性。在过滤相关数据时,何时使用每个运算符?有哪些细微差别可能影响性能和结果的准确性?

用 Hintsage AI 助手通过面试

答案。

问题背景:

EXISTS 和 IN 运算符用于基于子查询过滤记录。自 SQL 出现以来,开发人员一直在选择它们之间挣扎,试图了解哪种方式更快,以及在什么情况下它们的应用更优先。

问题:

主要任务是只获取在外部或内部表中有对应的行,这对于大数据集的性能始终至关重要。选择 EXISTS 和 IN 取决于子查询的结构、返回值的数量和唯一性,以及使用的数据库管理系统。

解决方案:

  • 当子查询返回少量唯一值时,IN 通常更有效。
  • 如果仅存在相应行的事实很重要,EXISTS 更可取;适用于返回成千上万行的大子查询。
  • 还需要注意 NULL 的特定行为以及不同数据库管理系统的优化差异。

代码示例:

-- 使用 IN SELECT name FROM students WHERE id IN (SELECT student_id FROM enrollments WHERE course = 'SQL'); -- 使用 EXISTS SELECT name FROM students WHERE EXISTS (SELECT 1 FROM enrollments WHERE enrollments.student_id = students.id AND enrollments.course = 'SQL');

关键特性:

  • EXISTS 在第一次匹配时结束搜索(嵌套子查询可以停止)。
  • IN 通常对短列表有效,但可能对长而不唯一的子查询较慢。
  • EXISTS 在存在 NULL 时表现正常,而 IN 在子查询中遇到 NULL 时可能出现意外行为。

有陷阱的问题。

如果子查询 IN 中遇到 NULL,会发生什么?

许多人认为 IN 只会忽略 NULL,但如果存在 NULL,结果可能是不可预测的。例如,查询:

SELECT id FROM orders WHERE client_id IN (1, NULL, 2);

技术上不会包括 client_id 不等于 1 或 2 的行,但如果子查询中的列表只有 NULL,结果将是空的。

EXISTS 和 IN 是完全可以互换的结构吗?

不是。使用 EXISTS 通常更快,因为不需要分析整个子查询。此外,IN 不适用于返回多个列的子查询,而 EXISTS 可以,因为比较是基于 WHERE 中的条件。例如:

SELECT col1 FROM t1 WHERE (col1, col2) IN (SELECT col3, col4 FROM t2);

这种选项通常不被支持,而类似的 EXISTS 则可以。

在处理索引字段时,IN 可能比 EXISTS 更快吗?

是的,如果子查询较小且比较的字段上有索引,IN 可能会更快。然而在大选择集或没有索引时,情况相反。

常见错误和反模式

  • 使用 IN 处理返回大量行的子查询。
  • 忽视子查询中存在 NULL 的后果。
  • 随意将 EXISTS 替换为 IN,而不分析查询计划。

生活中的例子

负面案例

分析师使用 IN 方法构建报告,而没有考虑子查询返回数十万行带有 NULL。报告运行了几分钟,有时会丢失数据。

优点:

  • 逻辑简单易懂 缺点:
  • 性能损失
  • 获得不正确信息的风险

正面案例

同样的查询在 EXISTS 上重写,并添加了额外条件,索引进行了重新计算。

优点:

  • 快速响应
  • 即使有大量子查询和 NULL 也能准确过滤 缺点:
  • 条件更复杂,需要测试执行计划