讲师中心 微信公众号
AI工具推荐 视频效率加速

为什么在SQL中先过滤数据再执行JOIN能大幅减少IO开销?

冬墨姑娘_9990

冬墨姑娘_9990

发布时间:2026-07-01 13:08:58

|

579人浏览过

|

来源于php中文网

原创

过滤应放在WHERE而非ON子句,尤其LEFT JOIN中ON后加单表条件无法下推;显式子查询提前剪枝最可靠;JOIN字段类型必须一致且有合适索引;避免SELECT *,用覆盖索引减少IO。

为什么在sql中先过滤数据再执行join能大幅减少io开销?

因为过滤能直接砍掉参与JOIN的原始数据量,而IO开销主要来自“读多少行”——不是JOIN逻辑本身慢,是没过滤就JOIN导致数据库被迫扫描、传输、临时写入海量中间行。

WHERE条件放错位置,IO可能翻十倍

很多人把过滤条件全塞进ON子句,尤其在LEFT JOIN里写ON ... AND status = 'active',这看似“提前过滤”,实则让优化器无法下推该条件到左表扫描阶段。结果是:左表全扫一遍,再连右表,最后才丢掉不匹配的行。

  • WHERE作用于JOIN之后的结果集,但对单表条件(如users.status = 'active'),优化器通常能下推到该表扫描时执行——真正减少磁盘读
  • ON只定义关联关系,不减少被驱动表的访问量,除非有索引下推(比如MySQL 8.0+对IN或等值条件的部分优化)
  • 典型反例:SELECT * FROM orders o LEFT JOIN users u ON o.user_id = u.id AND u.deleted = 0 → users仍被全表扫描;改成WHERE u.deleted = 0会失效左连接,正确做法是LEFT JOIN (SELECT * FROM users WHERE deleted = 0) u ON ...

用子查询或CTE显式提前剪枝

依赖优化器自动下推不可靠,尤其遇到OR、LIKE '%xx'、DATE(created_at)这类函数包裹字段时,下推大概率失败。显式子查询是最稳的控制方式。

  • 慢写法:SELECT u.name, o.amount FROM users u JOIN orders o ON u.id = o.user_id WHERE o.status = 'shipped' AND o.created_at > '2025-01-01' → 执行计划常显示rows_examined达百万级
  • 快写法:SELECT u.name, o.amount FROM users u JOIN (SELECT user_id, amount FROM orders WHERE status = 'shipped' AND created_at > '2025-01-01') o ON u.id = o.user_id → orders扫描行数从10万降到几百
  • 注意:子查询里必须有支撑索引,比如(status, created_at, user_id, amount),否则GROUP BY或WHERE本身又成全表扫

JOIN字段类型不一致,索引直接失效

哪怕只JOIN两张表,只要关联字段类型不匹配(比如user_id INT vs log.user_id VARCHAR),数据库就会放弃走索引,转为全表扫描——这时“先过滤”也救不了IO爆炸。

  • 隐式转换常见于日志表、宽表导出、跨系统同步场景,查EXPLAIN时注意type是否为ALL或index,Extra是否含Using where但无Using index
  • 修复方法不是加索引,而是统一字段类型:ALTER TABLE log MODIFY user_id INT UNSIGNED,再补索引
  • 复合索引顺序错误也会导致失效,例如想按status和user_id过滤,却建了(user_id, status) —— WHERE status = 'paid'无法用上该索引

SELECT * 或冗余字段会放大IO问题

每多选一个字段,尤其是TEXT、JSON、BLOB或宽字段(如50列的用户表),数据库就得从磁盘多读一页或多页,网络多传一次,内存多存一份——这些开销在JOIN后会被乘以关联行数。

  • 坏习惯:SELECT * FROM users u JOIN orders o ON u.id = o.user_id WHERE u.status = 'active' → 即使只要u.id和o.amount,也得把整行users和orders都捞出来
  • 覆盖索引可缓解:建INDEX idx_user_active (status, id, name, email),让WHERE status = 'active' + SELECT id, name全程走索引,不回表
  • ORM用户特别注意:Django默认.all()生成SELECT *,要用.values('id', 'name')或.only('id', 'name')显式约束

最常被忽略的点是:你以为的“小表驱动大表”,其实驱动表根本没索引,或者JOIN字段类型不一致——这时候无论怎么调WHERE位置、写多漂亮的子查询,IO都降不下来。先看EXPLAIN里的key和rows,再动手改SQL。

热门AI工具

更多
SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

AionClaw
AionClaw Hot

AionClaw是一款面向办公、创作和编程任务的AI桌面智能体。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

4003

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

851

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

1049

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

5861

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2783

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

5840

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

7761

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

1050

2024.04.29

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

80

2026.09.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
SQL优化与排查(MySQL版)
SQL优化与排查(MySQL版)

共26课时 | 3.2万人学习

MySQL索引优化解决方案
MySQL索引优化解决方案

共23课时 | 2.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn