慢查询优化
你说”我的接口很慢”。可能的原因:网络慢、Python 代码慢、数据库慢。
本章只讲怎么定位”数据库慢”——以及定位后怎么读体检报告。
1.1 先开慢查询日志
-- 查看慢查询日志是否开启(MySQL 默认关着的!)
SHOW VARIABLES LIKE 'slow_query_log%';
-- 开启慢查询日志(临时生效,重启 MySQL 失效)
SET GLOBAL slow_query_log = ON;
-- 设慢查询阈值——超过 1 秒的 SQL 都记下来
SET GLOBAL long_query_time = 1;
-- 查看慢查询日志文件位置
SHOW VARIABLES LIKE 'slow_query_log_file';
永久生效要改 MySQL 配置文件(my.cnf / my.ini):
[mysqld]
slow_query_log = 1
long_query_time = 1
slow_query_log_file = /var/log/mysql/slow.log
log_queries_not_using_indexes = 1 ← 没走索引的 SQL 也记下来(哪怕很快)
⚠️
long_query_time设多少?建议项目初期设 1 秒,上线跑几天改 0.5 秒,稳定后改 0.1 秒——越到后面越严格。被问”你们慢查询阈值是多少”,答”根据业务阶段调整”比答死一个数加分。
1.2 慢查询日志长什么样
# Query_time: 12.345678 Lock_time: 0.000123 Rows_sent: 10 Rows_examined: 500000
SELECT * FROM orders WHERE user_id = 42 ORDER BY created_at DESC;
逐行翻译:
Time → 这条 SQL 什么时候执行的
User@Host → 谁、从哪台机器发的
Query_time → 🔴 执行花了 12.3 秒(这是你看慢查询日志最关心的)
Lock_time → 等锁等了多久(0.0001 秒,几乎没等——说明慢不是锁的事)
Rows_sent → 最终返回了 10 行
Rows_examined → 🔴 为了找到这 10 行,扫描了 50 万行!
这就是慢的根源——扫了 50 万行才吐出 10 行。
说明索引有问题。
🔴 一句话讲清:“定位慢查询两层——第一层用慢查询日志找’谁慢’,第二层用 EXPLAIN 分析’为什么慢’。慢查询日志看 Query_time 和 Rows_examined,Rows_examined 远大于 Rows_sent 就是索引有问题。EXPLAIN 看 type 列和 Extra 列。“
1.3 没有慢查询日志时怎么现场抓慢 SQL
-- 实时看当前正在跑的所有查询(谁在跑、跑了多久、状态是什么)
SHOW FULL PROCESSLIST;
-- 输出例:
-- | Id | User | Host | db | Command | Time | State | Info |
-- | 15 | root | localhost:54321 | shop | Query | 23 | Sending data | SELECT * FROM orders... |
-- Time = 23 秒 → 这条 SQL 已经跑了 23 秒,还没跑完
-- State = Sending data → 正在扫表、传数据
-- 它就是当前的"慢查询嫌疑人"
SHOW PROCESSLIST 状态列速查:
状态 什么意思 该紧张吗?
─────────────────────────────────────────────────────────────────
Sending data 正在读数据/发数据——最常见 看 Time 多久
Sorting result 正在排序——ORDER BY 没走索引 该!
Creating tmp table 正在建临时表——GROUP BY 没走索引 该!
Locked 在等锁释放——别人占着数据不放手 该!
Sleep 连接闲着,啥也没干 不该,但太多说明没关连接
Statistics 正在决定用哪个索引 不该,偶尔出现正常
一图流(Mermaid)
flowchart TD A[接口慢] --> B{哪层慢?} B -->|数据库慢| C[第一步: 慢查询日志找 谁慢] C --> D[看 Query_time + Rows_examined] D --> E[第二步: EXPLAIN 分析 为什么慢] E --> F[看 type 列 + Extra 列] F --> G[Rows_examined 远大于 Rows_sent → 索引有问题] C -.没日志时.-> H[SHOW PROCESSLIST 现场抓 Time 长的]
速记卡(面试闪卡)
Q1:一句话讲清「慢查询优化」到底是什么?
A:慢查询优化两步走:先用慢查询日志找出”谁慢”,再用 EXPLAIN 分析”为什么慢”。
Q2:一、开慢查询日志找”谁慢” —— 怎么理解? —— 怎么理解?
A:像给数据库装体检仪:slow_query_log 打开、long_query_time 设阈值(初期 1s、上线 0.5s、稳定 0.1s),超过就记下来;log_queries_not_using_indexes 还能把没走索引的慢 SQL 也抓出来。英文:slow query log / long_query_time。
Q3:二、读日志看两个关键指标 —— 怎么理解? —— 怎么理解?
A:像看化验单盯两项:Query_time 是执行花了多久(最关心的);Rows_examined 是为找结果扫了多少行。若 Rows_examined 远大于 Rows_sent(扫 50 万才吐 10 行),根因就是索引有问题。英文:Rows_examined / Rows_sent。
Q4:三、没日志怎么现场抓 —— 怎么理解? —— 怎么理解?
A:像急诊先量生命体征:SHOW FULL PROCESSLIST 看当前在跑的查询,Time 长的、State 是 Sending data / Sorting result / Creating tmp table / Locked 的就是”慢查询嫌疑人”。英文:processlist / Sending data。
Q5:四、EXPLAIN 分析”为什么慢” —— 怎么理解? —— 怎么理解?
A:像给 SQL 拍 X 光:EXPLAIN 看 type 列(从 ALL 全表扫到 const 最佳,越左越慢)和 Extra 列(Using filesort / Using temporary 都是告警)。结合慢日志定位后,针对性建索引或改写 SQL。英文:EXPLAIN / type / Extra。
Q6:核心速记主线有哪些?
-
两步走:慢查询日志找”谁慢”,EXPLAIN 分析”为什么慢”
-
开日志:slow_query_log + long_query_time 阈值随业务收紧
-
看指标:Query_time 耗时、Rows_examined≫Rows_sent 即索引问题
-
现场抓:SHOW PROCESSLIST 盯 Time 长、State 异常的查询
-
深分析:EXPLAIN 看 type 列与 Extra 列,定位全扫/临时表
口诀
A:慢查询分两步走,日志先抓谁在兜;
Query_time 看耗时,扫行远超发送愁;
无日志用 PROCESSLIST,长时异常是根由;
EXPLAIN 拍 X 光,type Extra 指因由。