mysql中子查询的使用方法与性能优化-mysql教程

子查询在where中慢是因为相关子查询对每行外层数据都执行一次,导致n×m级扫描;应改用join、确保索引、避免函数索引失效,并用explain验证执行计划。

子查询写在 WHERE 里为什么慢得离谱

因为 MySQL 在 WHERE 子句中使用相关子查询(即子查询依赖外层表字段)时,可能对每行外层数据都执行一次子查询,形成 N×M 级扫描。比如:

SELECT * FROM orders o WHERE o.customer_id IN (SELECT id FROM customers c WHERE c.status = 'active' AND c.id = o.customer_id);

这里 c.id = o.customer_id 让子查询变成“相关”的,MySQL 5.6 及更早版本几乎无法优化,即使加了索引也常走全表扫描。

常见错误现象:EXPLAIN 显示 type 是 ALL 或 index,rows 列数值极大,Extra 出现 Using where; Using join buffer。

  • 优先改写为 JOIN:上例可转成 INNER JOIN customers c ON o.customer_id = c.id WHERE c.status = 'active'
  • 确认子查询是否真需“相关”:如果只是过滤固定集合,用非相关子查询(如 (SELECT id FROM customers WHERE status = 'active')),MySQL 能物化为临时表
  • MySQL 8.0+ 开启 optimizer_switch='materialization=on' 可提升非相关子查询性能,但不解决相关子查询本质问题

IN、EXISTS、JOIN 三者选哪个

语义不同,执行计划和性能差异明显,不能简单互换。

IN 适合右侧结果集小且无 NULL 值的场景;EXISTS 天然适合相关子查询,且对 NULL 安全;JOIN 最适合需要取子查询中额外字段或做聚合的场景。

  • IN 遇到 NULL 会整体返回空结果(如 1 IN (1,2,NULL) → UNKNOWN → 过滤掉该行),而 EXISTS 不受 NULL 影响
  • 当子查询结果集较大(比如 > 1000 行),IN 可能触发“IN-list limit”,MySQL 会退化为全表扫描;此时 EXISTS 或 JOIN 更稳
  • EXISTS 在有合适索引时通常走 range 或 ref,但必须确保子查询的关联字段上有索引(如 EXISTS (SELECT 1 FROM logs l WHERE l.order_id = o.id),需 logs(order_id) 索引)

子查询放在 SELECT 列表里要注意什么

标量子查询(返回单值、单行)可以出现在 SELECT 列表,但极易引发性能灾难,尤其在外层是大表时。

夏夕资源网专注于CMS网站模板,主流语言整站网站源码下载,网站建设相关教程分享,好用的软件素材整合下载,提供一站式便捷自助服务。
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,默认解压密码为"zy.lucklyus.top",如遇到无法解压的请联系管理员!
夏夕资源网-网站模板_免费源码_资源素材 » mysql中子查询的使用方法与性能优化-mysql教程
在线时间:12:00 - 22:00
关注微信公众号:微信公众号
站长邮箱:[email protected]
  • 运营天数: 1393+
  • 资源总数: 47989+
  • 用户总数: 1+
  • 今日更新: 0+
  • 访问次数: 4023092+
  • 本周更新: 0+
  • 最后更新: 2026-03-16

本站指数

×
  • 运营天数: 1393+
  • 资源总数: 47989+
  • 用户总数: 1+
  • 今日更新: 0+
  • 访问次数: 4023092+
  • 本周更新: 0+
  • 最后更新: 2026-03-16