SQL性能优化之子查询篇_减少中间结果集的大小

张开发
2026/4/11 8:16:41 15 分钟阅读

分享文章

SQL性能优化之子查询篇_减少中间结果集的大小
子查询慢主因是生成过大中间结果集应优先用EXPLAIN分析执行计划改IN为EXISTS外表小、内表大时、转JOIN或LEFT JOINGROUP BY确保关联字段有索引并避免盲目加DISTINCT或LIMIT。子查询返回太多行导致慢查怎么办子查询慢往往不是语法错而是它悄悄生成了远超需要的中间结果集。比如 WHERE id IN (SELECT user_id FROM logs WHERE created_at 2024-01-01)如果 logs 表没索引、数据量又大这个子查询可能扫几百万行再把几万 user_id 全拉出来去外层匹配——IO 和内存都扛不住。确认子查询是否真有必要先用 EXPLAIN 看执行计划重点看 rows 和 Extra 列如果出现 Using temporary; Using filesort 或 rows 明显远大于最终结果数说明中间集膨胀了 能转 JOIN 就别硬套子查询尤其是相关子查询含外层字段MySQL 8.0 对 JOIN 的优化远好于反复执行子查询 加上 LIMIT 或 DISTINCT 前要三思比如 SELECT * FROM users WHERE id IN (SELECT DISTINCT user_id FROM events)如果 events.user_id 本身有重复DISTINCT 会强制排序去重反而更慢不如先在 events 上建联合索引 (user_id, created_at)IN 子查询 vs EXISTS 子查询性能差异在哪IN 和 EXISTS 看似等价但执行逻辑完全不同IN 先算出完整子结果集再做哈希查找EXISTS 是对外表每行做一次“是否存在匹配”的半连接判断找到一个就停。外表小、内表大时优先用 EXISTS比如查“有没有订单的用户”users 表 1 万行orders 表 500 万行EXISTS (SELECT 1 FROM orders WHERE orders.user_id users.id) 通常比 IN (SELECT user_id FROM orders) 快得多 内表有高效索引时EXISTS 优势更明显确保 orders.user_id 有索引否则 EXISTS 也会退化成全表扫描 IN 不能处理 NULL如果子查询结果含 NULL整个 IN 表达式返回 UNKNOWN常被误判为“没匹配到”EXISTS 不受 NULL 影响 相关子查询被重复执行怎么避免相关子查询比如 SELECT name, (SELECT COUNT(*) FROM orders WHERE orders.user_id users.id) AS order_cnt FROM users在 MySQL 5.7 及更早版本中对 users 每一行都会重新执行一次子查询10 万用户 执行 10 万次子查询。 WisPaper 复旦大学研发的AI学术搜索工具5分钟内筛选1000篇论文

更多文章