sql 查询优化需分三步:先开启慢查询日志定位问题 sql,再用 explain 分析执行计划识别瓶颈(如 type=all、key=null),最后针对性建联合索引、避免索引失效并验证效果。

SQL 查询慢,核心要分三步走:先抓出来,再看为什么慢,最后动手改。不盲目加索引,也不靠猜——整套流程有迹可循、可复现、可验证。
一、开启并获取慢查询日志
慢 SQL 得先“看见”,否则优化无从谈起。MySQL 默认关闭慢查询日志,需主动启用:
- 临时开启(当前实例有效,重启失效):
SET GLOBAL slow_query_log = ON;SET GLOBAL long_query_time = 1;(建议设为 1 秒,生产环境可调至 0.5 秒)SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log'; - 永久生效:修改 my.cnf 的
[mysqld]段,加入slow_query_log = 1slow_query_log_file = /var/log/mysql/slow.loglong_query_time = 1log_queries_not_using_indexes = 1(辅助发现隐性低效 SQL) - 验证是否生效:
SHOW VARIABLES LIKE 'slow_query_log';SHOW STATUS LIKE 'Slow_queries';(该值会随慢 SQL 执行递增)
二、用 EXPLAIN 看清执行计划
日志里找到慢 SQL 后,别急着改,先运行 EXPLAIN + SQL,重点盯这几个字段:
- type:越靠前越好(
const≈ref>range>index>ALL)。出现ALL基本等于全表扫描。 - key:实际命中哪个索引?显示
NULL就是没走索引。 - rows:预估扫描行数。百万级表扫几十万行,大概率有问题。
- Extra:警惕
Using filesort(额外排序)、Using temporary(建临时表)、Using join buffer(关联缓存不足)。
例如对订单表查用户 + 时间范围:SELECT id, order_no FROM tb_order WHERE user_id = 10086 AND create_time >= '2025-01-01' AND delete_flag = 0;
若 EXPLAIN 显示 type=ALL、key=NULL,说明现有 idx_user_id 单列索引无法覆盖 create_time 和 delete_flag 条件。
三、针对性优化常见路径
90% 的慢 SQL 问题落在索引和写法上,优先检查这几类:
- 补联合索引 :按查询条件顺序建,遵循最左前缀。上例可建:
ALTER TABLE tb_order ADD INDEX idx_user_del_time (user_id, delete_flag, create_time);
注意字段顺序:等值条件(user_id、delete_flag)放前,范围条件(create_time)放最后。 - 避免索引失效 :
✅ 正确:WHERE create_time >= '2025-01-01'
❌ 失效:WHERE DATE(create_time) = '2025-01-01'(函数导致索引无法下推)
✅ 正确:WHERE status IN (1,2)
❌ 高风险:WHERE status != 0(可能跳过索引) - 减少数据传输量 :只查必要字段,避免
SELECT *;大分页用游标或延迟关联,别用LIMIT 1000000, 20。
四、辅助手段与验证闭环
光改完不行,得确认效果落地:
- 用
PROFILING查耗时分布(开启后执行 SQL,再SHOW PROFILE FOR QUERY N;),看是 I / O 卡住还是 CPU 计算拖慢。 - 对比优化前后
EXPLAIN的rows和type,必须有明显下降才算有效。 - 上线前在从库或压测环境实测 QPS、响应时间、CPU/IO 负载变化,避免“优化后更慢”。
慢 SQL 不是单点问题,而是数据库、SQL 写法、索引设计、甚至业务模型的综合反馈。定位准、分析透、改得稳,才能真正把性能攥在手里。






























