导读:本期聚焦于小伙伴创作的《为什么SQL中使用NOT IN比LEFT JOIN性能差_分析NULL值对执行计划的影响》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《为什么SQL中使用NOT IN比LEFT JOIN性能差_分析NULL值对执行计划的影响》有用,将其分享出去将是对创作者最好的鼓励。

在SQL查询中,经常需要实现查询A表中存在但B表中不存在的记录的需求,常见的实现方式有NOT IN和LEFT JOIN两种。很多实际案例显示NOT IN的查询性能往往弱于LEFT JOIN,这和NULL值的处理以及数据库执行计划的生成有直接关系。

为什么SQL中使用NOT IN比LEFT JOIN性能差_分析NULL值对执行计划的影响

两种查询方式的常规写法

假设我们有两个表,user表存储用户信息,order表存储订单信息,现在需要查询没有下过订单的用户,两种写法如下:

NOT IN写法

-- 查询没有下过订单的用户
SELECT u.id, u.name
FROM user u
WHERE u.id NOT IN (SELECT user_id FROM order);

LEFT JOIN写法

-- 查询没有下过订单的用户
SELECT u.id, u.name
FROM user u
LEFT JOIN order o ON u.id = o.user_id
WHERE o.user_id IS NULL;

NULL值对NOT IN逻辑的影响

NOT IN的逻辑是判断左侧值是否不在右侧子查询的结果集中,这个判断过程对NULL值非常敏感。SQL中NULL代表未知值,任何值和NULL进行比较的结果都是NULL,而不是TRUE或FALSE。

如果子查询SELECT user_id FROM order的结果中包含NULL值,那么整个NOT IN的判断逻辑就会出问题。比如当u.id等于5时,子查询结果里有NULL,那么5 NOT IN (1,2,NULL)的判断过程是:先判断5不等于1、5不等于2,这两个是TRUE,但5不等于NULL的结果是NULL,最终整个判断结果就是NULL,不会被判定为TRUE,这条记录就不会被返回。

更严重的是,数据库优化器在处理NOT IN时,如果检测到子查询可能返回NULL,就无法使用高效的索引查找策略,只能选择全表扫描或者更复杂的执行路径,这会直接导致性能下降。

LEFT JOIN的执行逻辑优势

LEFT JOIN的执行逻辑是先对两个表进行连接,然后过滤连接结果为NULL的记录。这种逻辑对NULL值的处理更明确:只有当右表没有匹配到记录时,右表的字段才会是NULL,过滤条件o.user_id IS NULL的判断逻辑非常清晰,不会受到右表字段是否为NULL的额外影响。

数据库优化器在处理LEFT JOIN时,可以更灵活地选择执行计划,比如先对右表的连接字段建立索引,使用嵌套循环连接或者哈希连接等高效策略,只要右表的user_id字段有索引,就能快速定位匹配的记录,执行效率更高。

执行计划层面的差异对比

我们可以通过EXPLAIN命令查看两种写法的执行计划,以下是两种写法的典型执行计划对比:

对比项NOT IN写法执行计划LEFT JOIN写法执行计划
访问类型子查询全表扫描,主表全表扫描主表全表扫描,右表索引范围扫描
临时表使用可能会生成临时表存储子查询结果一般不需要临时表
索引利用率子查询字段有索引也可能无法使用右表连接字段索引可以被正常利用
预估执行行数子查询结果集大时预估行数不准预估行数更准确

从执行计划可以看出,NOT IN写法因为NULL值的潜在影响,优化器很难生成最优的执行策略,而LEFT JOIN的逻辑更明确,优化器可以生成更高效的执行路径。

实际开发中的优化建议

  • 如果子查询的字段明确不可能为NULL(比如字段有NOT NULL约束),并且数据量较小,NOT IN和LEFT JOIN的性能差距可能不大,但仍建议优先使用LEFT JOIN。
  • 如果子查询的字段允许为NULL,绝对不要使用NOT IN,避免逻辑错误和性能问题。
  • 无论使用哪种写法,都要确保连接字段或者子查询的字段有合适的索引,这是提升查询性能的基础。
  • 对于数据量大的表,尽量通过EXPLAIN命令查看执行计划,确认查询是否使用了预期的索引,避免全表扫描。

总结

NOT IN比LEFT JOIN性能差的核心原因是NULL值对NOT IN逻辑判断的干扰,导致数据库优化器无法生成高效的执行计划。LEFT JOIN的处理逻辑对NULL值更友好,优化器可以更好地利用索引和高效的连接策略。实际开发中,实现存在性否定查询时,优先选择LEFT JOIN加IS NULL的写法,既能避免NULL值带来的逻辑问题,也能获得更好的查询性能。

SQLNOT_INLEFT_JOINNULL值执行计划修改时间:2026-06-14 02:57:33

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。