查订单列表要带上用户昵称,两张表一拼发现少了十几条记录,原因是用了 inner join,用户表里被删掉的账号把订单一起过滤掉了。mysql join 几种连接方式,差别就在保留哪边的行。
inner join 只留两边都匹配的
SELECT o.id, u.name FROM orders o INNER JOIN users u ON o.user_id = u.id;,用户不存在的订单直接不出现。做对账、做精确统计时这通常是想要的,做列表展示就容易丢数据,先想清楚业务要哪边。如果业务上用户一定存在,inner join 反而能提早暴露脏数据。
left join 保住左表全部行
把上面的 INNER 换成 LEFT,订单全在,匹配不到用户的昵称显示 NULL,用 IFNULL 给个默认值就行。right join 反过来,实际项目里用得少,多数人习惯调换表的顺序,统一写 left join,读起来顺。
on 和 where 放哪结果不一样
left join 时条件写在 on 里,不匹配的右表行不参与连接,左表照样保留;写在 where 里,等于连接完再过滤,NULL 那些行会被筛掉,效果退化成 inner join。统计「每个用户有多少订单」时特别容易踩这个坑。
数据量大了看索引和执行计划
join 的字段两边都要有索引,类型和字符集保持一致,否则可能用不上。用 EXPLAIN 看执行计划,出现全表扫描或者 Using join buffer 就该调整了。三张表以上关联时先过滤再连接,别一上来就把大表整个拉进来。联合索引注意最左前缀,只在第二个字段上过滤是用不上的。
连接顺序也影响速度,小表驱动大表一般更快。MySQL 优化器多数时候能自己选对,用 STRAIGHT_JOIN 强制顺序之前,先确认它确实选错了。
选法其实简单:要两边交集用 inner,要主表全量用 left,条件放 on 还是 where 先想清楚语义。mysql join 写错多半不是语法问题,是没想明白要保留谁。写完先在测试库跑 EXPLAIN,别等上线翻慢查询日志。