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写法、索引设计、甚至业务模型的综合反馈。定位准、分析透、改得稳,才能真正把性能攥在手里。










