mysql多表关联查询如何使用索引_mysql联表查询优化

7次阅读

多表join性能关键在索引:右表关联字段必须建索引,复合索引需按join字段、等值过滤、范围查询顺序排列,必要时用straight_join强制驱动表,且避免select*及大字段拖累。

mysql多表关联查询如何使用索引_mysql联表查询优化

WHERE 条件字段没加索引,JOIN 就白搭

多表 JOIN 时,mysql 不会自动给关联字段建索引。哪怕 ON a.id = b.a_id 写得再规范,只要 b.a_id 没索引,就会触发全表扫描——尤其是 b 表数据量一大,查询直接变慢十倍以上。

实操建议:

  • 先用 EXPLAIN 看执行计划,重点检查 type 列是否为 ALLindex(说明没走有效索引)
  • JOIN 的右表(被驱动表)关联字段必须建索引,比如 LEFT JOIN orders o ON u.id = o.user_ido.user_id 要有索引
  • 左表主键或唯一字段天然适合做驱动条件,但若用非主键字段 JOIN(如 u.email),那它也得加索引

复合索引顺序决定 JOIN + WHERE 是否能共用

当查询同时含 JOINWHERE(比如 WHERE status = 'paid' AND created_at > '2024-01-01'),单列索引往往不够。MySQL 只能用上复合索引的最左前缀,顺序错了,索引就废一半。

举例:想加速 SELECT * FROM users u JOIN orders o ON u.id = o.user_id WHERE o.status = 'paid' AND o.created_at > '2024-01-01',应该建:

ALTER TABLE orders ADD INDEX idx_user_status_created (user_id, status, created_at);

原因:user_id 是 JOIN 条件,放最左;status 是等值过滤,放中间;created_at 是范围查询,放最后——这样三者才能被同一索引覆盖。

常见错误:

  • created_at 放最左,导致 user_id 无法走索引
  • 只建 (status, user_id),范围条件在前,user_id 实际失效

STRAIGHT_JOIN 强制驱动表顺序有时比优化器更靠谱

MySQL 优化器默认选“预估行数少”的表当驱动表,但统计信息过期或数据倾斜时,它可能选错。比如小表 categories 有 10 行,大表 products 有 100 万行,但优化器误判 products 更小,结果先扫百万行再匹配,性能崩盘。

这时可手动指定:

SELECT /*+ STRAIGHT_JOIN */ ... FROM categories c JOIN products p ON p.cat_id = c.id;

或旧版本用:

SELECT STRAIGHT_JOIN ... FROM categories c JOIN products p ON p.cat_id = c.id;

注意点:

  • 仅当 EXPLAIN 明确显示驱动表不合理时才干预
  • 加了 STRAIGHT_JOIN 后务必验证执行计划,避免硬编码反而更慢
  • 线上变更前,在从库或测试环境压测,因为不同数据分布下最优路径可能不同

避免 SELECT * 和 json/TEXT 字段拖垮 JOIN 性能

很多人忽略:即使索引全对、驱动表合理,SELECT * 仍可能让 JOIN 变慢。尤其当某张表含大字段(TEXTJSON、长 VARCHAR),MySQL 在临时表或排序时需加载整行数据,内存和磁盘 I/O 压力陡增。

实操建议:

  • 只查真正需要的字段,例如 SELECT u.name, o.amount, o.status,而不是 SELECT *
  • 如果必须返回大字段,考虑拆成两次查询:先用高效 JOIN 拿主键,再用主键 IN 子查询单独取大字段
  • 检查 EXPLAIN 中的 Extra 列,出现 using temporaryUsing filesort 时,大概率是字段过多或类型不匹配引发的

索引不是建了就生效,关键看它能不能同时覆盖 JOIN 条件、过滤条件和查询字段——漏掉任意一环,性能拐点就藏在看似正确的 SQL 里。

text=ZqhQzanResources