MySQL 索引和查询优化怎么做:联合索引、ORDER BY、ON 与 WHERE

1次阅读
没有评论

MySQL 查询优化不能只问“有没有索引”。一条 SQL 慢,可能和返回列、JOIN、过滤条件、排序、分页、回表和数据分布都有关系。索引只是其中一环,真正要看查询路径。

新增索引前先看查询形态

建索引前先判断 SQL 的主要形态:

  • 等值查询。
  • 范围查询。
  • 排序。
  • 分页。
  • JOIN。
  • 聚合。
  • 覆盖索引。

不要只为单条 SQL 建孤立索引。更稳的做法是先盘点同一张表的高频查询,优先扩展已有联合索引,避免索引数量失控。

大表加索引要估算时间和风险

千万级甚至亿级表加索引,耗时可能从几分钟到数小时不等,取决于:

  • 表数据量。
  • 索引字段大小。
  • 机器 IO。
  • 云数据库规格。
  • 是否在线 DDL。
  • 当前业务写入压力。

比如给手机号字段增加普通索引:

alter table t_coupon add index idx_member_mobile(member_mobile);

执行前要确认业务低峰期、备份、锁表风险和回滚方案。

ORDER BY 不只是排序字段有没有索引

ORDER BY 的性能取决于过滤条件、排序字段和返回数据量。常见情况:

  • 过滤条件能缩小很多数据,排序压力小。
  • 排序字段有索引,但过滤后仍需要回表或文件排序。
  • 联合索引顺序不匹配,导致索引用不上排序。
  • 返回列太宽,导致 IO 成本高。

优化时先用 EXPLAIN 看访问类型、rows、key 和 extra。不要只看到排序字段有索引就认为一定快。

ON 和 WHERE 的位置会影响语义

JOIN 条件放在 ONWHERE 后,语义可能不同,尤其是外连接。

示例:

select *
from orders o
left join users u on o.user_id = u.id and u.status = 1;

这里会保留左表记录,只是右表只连接符合状态的用户。

如果写成:

select *
from orders o
left join users u on o.user_id = u.id
where u.status = 1;

WHERE 会在连接结果之后过滤,可能把没有匹配右表的记录过滤掉,使 LEFT JOIN 更接近 INNER JOIN

所以优化前先确认语义,不要为了“看起来更快”改变结果集。

冗余字段要看读写比例

冗余字段可以减少 JOIN,但不是银弹。判断时看:

  • 查询是否高频。
  • 更新是否低频。
  • 字段一致性是否可维护。
  • 是否能接受异步同步。
  • 是否有校验和修复脚本。

读多写少、字段变化低频的场景,冗余字段有价值;写多读少或一致性要求极高的场景,冗余字段可能反而制造维护成本。

深分页要换思路

大 offset 分页慢,不是简单加索引就能解决。常见优化:

  • 延迟关联:先查主键,再回表查详情。
  • 游标分页:用上一次的排序键继续查。
  • 限制最大页数。
  • 改成搜索或筛选驱动。

分页越深,数据库越像在做大量丢弃工作。能改交互时,优先改交互。

实用结论

MySQL 索引优化的核心是查询路径。先用 EXPLAIN 看执行计划,再看过滤、排序、回表、JOIN 和分页。新增索引要服务一组查询,而不是单条 SQL;ON 和 WHERE 要先保证语义正确,再谈性能。

正文完
 0
bdspAdmin
版权声明:本站原创文章,由 bdspAdmin 于2026-07-05发表,共计1194字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)