一句话总结
大小表联表查询优化的核心原则是小表驱动大表,确保被驱动表关联字段有索引,先过滤再JOIN,避免SELECT *,必要时冗余字段或改用子查询。
初级理解
小表驱动大表:在JOIN操作中,MySQL优化器会自动选择小表作为驱动表。驱动表越小,外层循环次数越少,性能越好。
确保索引:被驱动表的关联字段必须有索引,否则会导致大表全表扫描。
-- 小表驱动大表示例
SELECT * FROM small_table s
LEFT JOIN big_table b ON s.id = b.small_id
WHERE s.status = 1;
一句话总结:小表驱动大表 + 被驱动表关联字段有索引 = 联表查询优化的基础。
中级深入
减少JOIN数据量:先过滤再JOIN,而非JOIN后再WHERE。
-- 优化前:先JOIN后过滤
SELECT * FROM small s
JOIN big b ON s.id = b.sid
WHERE s.status = 1;
-- 优化后:先过滤后JOIN
SELECT * FROM (SELECT * FROM small WHERE status = 1) s
JOIN big b ON s.id = b.sid;
只查必要字段:避免SELECT *,减少IO和网络传输。
覆盖索引:让查询所需字段全部包含在索引中,避免回表。
注意:如果频繁JOIN,可以考虑将小表的关键字段冗余到大表中,避免JOIN操作。
高级拓展
子查询优化:优先使用JOIN替代子查询,MySQL对子查询优化有限。
-- IN子查询改写为JOIN
-- 差
SELECT * FROM users WHERE id IN (SELECT user_id FROM orders);
-- 好
SELECT u.* FROM users u
JOIN orders o ON u.id = o.user_id;
EXISTS vs IN:当外表小、内表大时,EXISTS可以利用内表索引快速返回。
派生表物化:MySQL 5.6+支持将子查询结果物化为临时表并加索引,但仍不如显式JOIN可控。
面试加分项:能说出小表驱动大表的原理、索引优化策略、子查询改写技巧,说明你对MySQL优化有深入理解。
实战场景
场景:电商订单表与用户表联表查询
-- 问题:订单表1000万,用户表100万,查询最近30天的订单及用户信息
-- 优化后:先过滤订单表(小表驱动大表)
SELECT o.*, u.username, u.phone
FROM (SELECT * FROM orders WHERE create_time > DATE_SUB(NOW(), INTERVAL 30 DAY)) o
JOIN users u ON o.user_id = u.id;
面试模拟
Q:为什么LEFT JOIN时左表必须是小表?
A:因为LEFT JOIN的语义决定了左表是驱动表,MySQL会遍历左表每一行,然后去右表通过索引查找匹配行。驱动表越小,外层循环次数越少,性能越好。
Q:如何判断联表查询是否使用了索引?
A:使用EXPLAIN分析执行计划,重点关注type列(至少达到ref级别)、key列(是否命中索引)、rows列(扫描行数)。如果type为ALL,说明全表扫描,必须优化。