执行计划需重点关注 type、key、rows 和 Extra 四列:type 为 ALL 表示全表扫描,key 为空说明未用索引,rows 远大于结果集表明索引选择不当,Extra 含 Using filesort 或 temporary 意味着排序 / 分组未走索引。

怎么看执行计划:用 EXPLAIN 抓住关键瓶颈
直接在 SQL 前加 EXPLAIN 是最快速判断性能问题的方式,它不真正执行查询,只返回 MySQL 的执行策略。重点关注 type、key、rows 和 Extra 这四列:
-
type值为ALL表示全表扫描,基本等于没走索引;range或ref更健康 -
key为空说明没用上索引,即使字段上有索引也可能因类型隐式转换或函数包裹失效 -
rows是预估扫描行数,远大于实际结果集时,大概率存在索引选择不当或过滤条件低效 -
Extra出现Using filesort或Using temporary是典型信号,意味着排序或分组没走索引
慢查询日志怎么开:别只靠 SHOW PROCESSLIST
SHOW PROCESSLIST 只能看“正在跑”的语句,对已结束的慢查询毫无办法。真正有用的是开启慢查询日志:
- 临时启用:
SET GLOBAL slow_query_log = ON;,配合SET GLOBAL long_query_time = 1;(单位秒) - 永久生效需改配置文件
my.cnf,加slow_query_log = 1和slow_query_log_file = /var/log/mysql/mysql-slow.log - 注意
log_queries_not_using_indexes默认关闭,如需记录“没走索引但不慢”的语句,得手动打开 - 日志里每条记录带
Query_time、Lock_time、Rows_sent、Rows_examined,后两者差异过大说明有无效扫描
索引不是越多越好:哪些字段适合建索引
索引提升查询,但拖慢写入,且占用磁盘和内存。建索引前先确认是否满足以下任一场景:
- WHERE 条件中高频出现的字段,尤其是等值(
=)、范围(>,BETWEEN)查询 - ORDER BY 或 GROUP BY 的字段,避免
Using filesort;注意升序 / 降序在 MySQL 8.0+ 才支持混合方向索引 - JOIN 的 ON 字段,两边字段类型、字符集、是否允许 NULL 必须严格一致,否则索引失效
- 复合索引要遵循最左前缀原则:
INDEX(a,b,c)能用于WHERE a=1、WHERE a=1 AND b>2,但不能用于WHERE b=2
为什么 SELECT * 在大表里特别伤
不只是网络传输多,更关键的是它让优化器难以决策、容易触发临时表和文件排序:
- 如果只查几列但用了
SELECT *,MySQL 可能放弃覆盖索引(Covering Index),转而回表查聚簇索引,I/O 暴增 - 当结果集字段包含
TEXT或BLOB类型,MySQL 会强制使用磁盘临时表(On disk internal temporary table),哪怕只有几百行 - 应用层用 ORM 自动生成
SELECT *时尤其危险——字段增加后查询可能突然变慢,却没人意识到是这里引发的 - 替代方案:明确列出所需字段,并确保这些字段能被已有索引覆盖;必要时建联合索引把查询字段全包进去
真实线上问题往往卡在「以为走了索引,其实没走」或者「走了索引但回表太重」,比参数调优更值得花时间盯紧 EXPLAIN 输出和慢日志里的 Rows_examined。