INNER JOIN 可自由选择小表驱动并利用索引优化,LEFT JOIN 左表固定驱动且右表缺索引易致全表扫描;连接字段需类型一致、均有索引,避免函数操作;多表JOIN应优先过滤、ON中写强条件; EXISTS 比 LEFT JOIN + IS NULL 更高效;GROUP BY/ORDER BY 需覆盖索引;隐式类型转换会使索引失效。

INNER JOIN 和 LEFT JOIN 的执行差异直接影响查询速度
MySQL 在执行 INNER JOIN 时可自由选择驱动表(即先扫描哪张表),优化器通常会选小表做驱动,配合索引快速过滤;而 LEFT JOIN 的左表固定为驱动表,右表必须全量匹配,若右表缺少关联字段索引,就会触发全表扫描 —— 这是慢查询最常见诱因之一。
- 检查执行计划:用
EXPLAIN SELECT ...看type是否为ref或range,避免出现ALL - 连接字段必须有索引:不仅左表的
ON字段要索引,右表对应字段也得有,且类型、字符集、是否允许 NULL 都需一致 - 避免在
ON条件里对字段做函数操作,比如ON YEAR(t1.create_time) = YEAR(t2.time)会让索引失效
JOIN 多张表时顺序和条件位置决定性能上限
MySQL 5.7+ 默认使用 BNL(Block Nested-Loop)算法,但表越多、中间结果集越大,内存缓冲越容易溢出到磁盘,性能断崖式下降。真正关键的是:把能最快过滤数据的表放在前面,并把强过滤条件尽量写进 ON 而非 WHERE。
-
ON是连接时生效,能减少临时连接结果集大小;WHERE是连接完成后再过滤,可能已生成百万行中间数据 - 三表连接如
t1 JOIN t2 ON ... JOIN t3 ON ...,优先让t1和t2先产出最小结果集,再连t3;可通过STRAIGHT_JOIN强制顺序(慎用) - 如果某张表只是用来取少量字段(如字典表),考虑用
(SELECT ... FROM dict WHERE id = t1.type_id LIMIT 1)替代JOIN,避免扩大结果集
用 EXISTS 替代 LEFT JOIN + IS NULL 判断空关联
想查“在 A 表中存在、但在 B 表中无匹配记录”的数据时,很多人写 LEFT JOIN ... WHERE b.id IS NULL,这会导致 MySQL 先做全连接再过滤,效率极低。改用 EXISTS 可让优化器提前终止搜索。
瑞宝通B2B系统使用当前流行的JAVA语言开发,以MySQL为数据库,采用B/S J2EE架构。融入了模型化、模板、缓存、AJAX、SEO等前沿技术。与同类产品相比,系统功能更加强大、使用更加简单、运行更加稳 定、安全性更强,效率更高,用户体验更好。系统开源发布,便于二次开发、功能整合、个性修改。 由于使用了JAVA开发语言,无论是在Linux/Unix,还是在Windows服务器上,均能良好运行
SELECT a.* FROM user a WHERE NOT EXISTS ( SELECT 1 FROM order b WHERE b.user_id = a.id );
-
NOT EXISTS在找到第一个匹配就停止,适合“是否存在”类逻辑 - 确保子查询中的关联字段(如
b.user_id)有索引,否则仍是全表扫 - 不要写
SELECT *在子查询里,只用SELECT 1即可,语义清晰且不增加解析开销
JOIN 查询中 GROUP BY 和 ORDER BY 容易引发临时表和文件排序
当 JOIN 后跟 GROUP BY 或 ORDER BY,MySQL 常常需要创建内部临时表并排序,尤其在没命中索引时会用 Using filesort 或 Using temporary —— 这两个提示几乎等于性能红灯。
- 复合索引要覆盖所有
GROUP BY字段,且顺序与语句中一致;如GROUP BY a, b,索引应建为(a, b),而非(b, a) - 如果
ORDER BY字段来自关联表(如ORDER BY t2.updated_at),且该字段不在驱动表上,基本无法避免文件排序 - 考虑在应用层分页:先用主键范围查询(如
WHERE id > ? LIMIT 20),再按需 JOIN,比直接LIMIT+JOIN更可控
实际调优时最容易被忽略的,是连接字段的隐式类型转换 —— 比如 user.id 是 BIGINT,而 order.user_id 是 VARCHAR,MySQL 会把整列转成数字比较,索引完全失效。这类问题不会报错,只会默默变慢。









