为什么LEFT JOIN比INNER JOIN更容易拖慢查询
因为LEFT JOIN必须保留左表所有行,即使右表没匹配项也要补NULL,优化器无法像INNER JOIN那样基于右表条件提前剪枝。一旦左表大、右表没索引,就会触发全表扫描+嵌套循环,性能断崖式下跌。
检查执行计划:EXPLAIN SELECT ... LEFT JOIN ...,重点关注
type是否为
ALL或
index,
rows是否远超预期 右表JOIN字段必须有索引——不是“最好有”,是“必须有”。例如
ON t1.user_id = t2.id,
t2.id需为主键或至少有单独索引 避免在JOIN条件中对字段做函数操作,如
ON t1.user_id = CAST(t2.uid AS SIGNED)会失效索引
复合索引怎么建才让JOIN和WHERE同时生效
复合索引顺序决定它能否支撑JOIN + 过滤 + 排序。核心原则:等值条件字段放最左,范围条件(
、<code>BETWEEN)放右,排序字段可追加但不参与索引查找。 典型场景:查询
SELECT * FROM orders o JOIN users u ON o.user_id = u.id WHERE u.status = 'active' AND o.created_at > '2024-01-01' ORDER BY o.amount DESC推荐索引:
CREATE INDEX idx_users_status_id ON users(status, id)(让JOIN用
id、WHERE用
status) 订单表索引应为:
CREATE INDEX idx_orders_user_created ON orders(user_id, created_at, amount)——
user_id支撑JOIN,
created_at过滤,
amount避免排序临时表
EXISTS替代JOIN真的更优?看这三种情况
EXISTS只关心子查询是否存在结果,不取数据,某些场景下能跳过大量匹配尝试。但它不是万能加速器,盲目替换可能更慢。
当右表极大、且只需判断存在性时(如“查所有有订单的用户”),EXISTS通常比
INNER JOIN快,因可短路 当需要右表字段(如
orders.order_no)或右表有多行匹配左表一行时,
EXISTS无法返回这些值,强行改写要加子查询或
LATERAL,反而复杂 MySQL 8.0+对
IN (SELECT ...)做了半连接优化,效果接近
EXISTS,但低版本仍建议显式写
EXISTS
JOIN后COUNT(*)突然变慢,90%是因为没加STRAIGHT_JOIN
MySQL优化器有时会选错驱动表,尤其多表JOIN+聚合时。比如
t1仅100行,
t2有千万行,却以
t2为驱动表去关联
t1,导致重复扫描
t1千万次。 用
EXPLAIN FORMAT=JSON确认
table顺序与
rows预估是否合理 强制指定驱动表:
SELECT STRAIGHT_JOIN COUNT(*) FROM t1 JOIN t2 ON t1.id = t2.t1_id WHERE t1.status = 'done';注意:
STRAIGHT_JOIN绕过优化器,后续表结构或数据分布变化后可能失效,需定期复查
索引不是建了就完事,JOIN顺序、驱动表选择、条件字段是否参与索引查找——这些细节在慢查询里往往比SQL写法本身影响更大。
