MySQL慢查询定位
MySQL慢查询定位
引言
网站访问缓慢很多根源是执行时间过长的SQL。开启MySQL慢查询日志,可以捕获执行超时SQL,找到需要优化的语句,是数据库性能排查的核心手段。
慢查询基础配置
慢查询日志会记录执行时长超过指定阈值的SQL语句。
-- 查看慢查询是否开启
SHOW VARIABLES LIKE 'slow_query_log';
-- 设置阈值,单位秒,超过1秒就记录
SET GLOBAL long_query_time =1;
常用分析工具
- mysqldumpslow:mysql自带工具,统计慢日志
mysqldumpslow -s t /var/lib/mysql/slow.log - pt-query-digest:percona工具,分析效果更强,适合大量日志。
优化排查流程
- 开启慢查询,收集慢SQL;
- 使用explain查看执行计划,判断是否缺少索引;
- 优化where条件,添加合适索引,改写SQL逻辑;
- 优化完成后,持续观察慢日志确认效果。
示例
EXPLAIN SELECT * FROM article WHERE title like '%PHP%';
看type字段,ALL代表全表扫描,是需要优化的信号。
总结
慢查询日志用来抓取低效SQL,但是开启会少量增加服务器IO压力,生产环境可以按需开启。定位到慢SQL后优先检查索引,再调整SQL写法,解决数据库卡顿问题。
MySQL慢查询排查,explain分析SQL执行计划
前言
网站突然变慢,数据库CPU100%?多半是慢查询搞的鬼。本文讲怎么开启慢查询日志、用explain分析SQL执行计划,找到慢的原因。
一、开启慢查询日志
临时开启
-- 查看慢查询是否开启
SHOW VARIABLES LIKE 'slow_query_log';
-- 开启慢查询
SET GLOBAL slow_query_log = ON;
-- 超过1秒就算慢查询
SET GLOBAL long_query_time = 1;
永久开启
编辑my.cnf:
vi /etc/my.cnf
加:
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
重启MySQL:
systemctl restart mysqld
看慢查询日志
tail -f /var/log/mysql/slow.log
二、explain是什么
explain用来分析SQL是怎么执行的,看有没有用索引、扫了多少行。
用法
EXPLAIN SELECT * FROM users WHERE name = '张三';
三、explain字段解释
id
SELECT的标识符,越大越先执行。
select_type
查询类型:
- SIMPLE:简单查询
- PRIMARY:主查询
- SUBQUERY:子查询
table
查的哪张表。
type(最重要)
访问类型,从好到差:
| 类型 | 含义 |
|---|---|
| system | 表只有一行 |
| const | 主键或唯一索引匹配,只查一行 |
| eq_ref | 主键或唯一索引匹配 |
| ref | 普通索引匹配 |
| range | 索引范围查询(between、>、<) |
| index | 扫整个索引树 |
| ALL | 全表扫描(最坏!) |
重点看: 出现ALL就是全表扫描,要加索引。
possible_keys
可能用到的索引。
key
实际用到的索引。
key是NULL就是没用到索引。
rows
预估要扫描多少行。
越大越慢。
Extra
额外信息:
| 值 | 含义 |
|---|---|
| Using where | 服务器在存储引擎返回后再过滤 |
| Using index | 用了覆盖索引,不错 |
| Using temporary | 用了临时表,不好 |
| Using filesort | 用了文件排序,不好 |
四、常见慢查询原因
原因1:没加索引
SELECT * FROM users WHERE name = '张三';
name字段没索引 → 全表扫描 → 慢。
解决: 加索引
ALTER TABLE users ADD INDEX idx_name(name);
原因2:索引失效
虽然加了索引,但SQL写法不对,索引用不上。
索引失效的情况:
-
对索引字段用函数:
SELECT * FROM users WHERE LEFT(name, 3) = '张三'; -- 索引失效 -
索引字段用运算:
SELECT * FROM users WHERE age + 1 = 20; -- 索引失效 -
最左前缀原则不满足:
-- 联合索引(a, b, c) SELECT * FROM t WHERE b = 1; -- 索引失效 -
like以%开头:
SELECT * FROM users WHERE name LIKE '%张三%'; -- 索引失效 -
类型不匹配:
-- phone是varchar SELECT * FROM users WHERE phone = 13800138000; -- 索引失效
原因3:SELECT *
查了不需要的字段,占内存。
解决: 只查需要的字段
SELECT id, name FROM users WHERE ...
原因4:大表分页越查越慢
SELECT * FROM users ORDER BY id LIMIT 100000, 10;
慢的原因: 要先扫10万行再跳过。
解决:
SELECT u.* FROM users u
INNER JOIN (SELECT id FROM users ORDER BY id LIMIT 100000, 10) t
ON u.id = t.id;
五、实战案例
慢SQL
SELECT * FROM orders WHERE user_id = 123 AND status = 1 ORDER BY create_time DESC LIMIT 10;
explain分析
EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND status = 1 ORDER BY create_time DESC LIMIT 10;
发现: type是ALL,key是NULL → 全表扫描。
加索引
ALTER TABLE orders ADD INDEX idx_user_status_time(user_id, status, create_time);
再explain: type变成ref,key是idx_user_status_time → 用上索引了。
六、优化原则
- WHERE条件加索引
- ORDER BY字段加索引
- 联合索引遵守最左前缀
- **不要SELECT ***
- 避免在索引字段上用函数
- 大分页用子查询优化
七、常见坑
坑1:加了索引但没用
原因: SQL写法导致索引失效。
排查: explain看key字段。
坑2:索引加太多
索引不是越多越好,写的时候要维护索引,会变慢。
建议: 单表索引不超过5个。
坑3:区分度低的字段不加索引
比如gender(男/女),加索引没用。
原则: 区分度高的字段加索引。
总结
记住:
- 开启慢查询日志找慢SQL
- 用explain分析SQL执行计划
- type=ALL就是全表扫描,要加索引
- key=NULL就是没用到索引
- rows越大越慢
- 索引失效要避免
最常用:
EXPLAIN SELECT * FROM users WHERE ...
遇到问题加QQ23979811 协助处理
MySQL查看慢查询日志,long_query_time参数
前言
网站突然变慢,不知道哪条SQL拖后腿。开慢查询日志,把跑得慢的SQL都抓出来优化。
一、什么是慢查询日志
慢查询日志(slow query log)记录执行时间超过阈值的SQL语句。
作用: 找到慢SQL,优化它们。
二、查看是否开启
SHOW VARIABLES LIKE 'slow_query_log';
| Variable_name | Value |
|---|---|
| slow_query_log | OFF |
OFF就是没开。
三、开启慢查询日志
方法1:临时开启(重启失效)
-- 开启
SET GLOBAL slow_query_log = ON;
-- 设置阈值(超过2秒算慢)
SET GLOBAL long_query_time = 2;
方法2:永久开启
改my.cnf:
[mysqld]
# 开启慢查询
slow_query_log = 1
# 慢查询阈值(秒)
long_query_time = 2
# 慢查询日志文件位置
slow_query_log_file = /var/log/mysql/slow.log
# 没走索引的SQL也记下来(可选)
log_queries_not_using_indexes = 1
重启MySQL:
systemctl restart mysqld
四、查看慢查询日志
直接看文件
tail -f /var/log/mysql/slow.log
用mysqldumpslow分析
MySQL自带的分析工具:
# 按查询时间排序,取前10
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
常用参数:
| 参数 | 说明 |
|---|---|
| -s t | 按时间排序 |
| -s c | 按次数排序 |
| -s l | 按锁时间排序 |
| -t 10 | 取前10条 |
| -g | 过滤关键词 |
示例:
# 按次数最多的排
mysqldumpslow -s c -t 20 /var/log/mysql/slow.log
# 只看select语句
mysqldumpslow -g "select" /var/log/mysql/slow.log
五、用pt-query-digest分析
更专业的分析工具(需要安装):
pt-query-digest /var/log/mysql/slow.log
输出更详细的统计报告。
六、常用参数说明
| 参数 | 默认值 | 说明 |
|---|---|---|
| slow_query_log | OFF | 是否开启 |
| long_query_time | 10 | 慢查询阈值(秒) |
| slow_query_log_file | 主机名-slow.log | 日志文件位置 |
| log_queries_not_using_indexes | OFF | 没走索引的也记 |
| log_output | FILE | 日志输出方式(FILE/TABLE) |
七、优化慢SQL
找到慢SQL后怎么优化:
1. 加索引
EXPLAIN SELECT * FROM users WHERE name = '张三';
看type是不是ALL,是ALL说明没走索引。
2. 避免select *
只查需要的字段:
-- 别这样
SELECT * FROM users;
-- 这样
SELECT id, name FROM users;
3. 避免大表全表扫描
加where条件,加limit。
4. 优化分页
大表分页越查越慢,用游标分页。
常见坑
坑1:long_query_time设太小
设成0.1秒,日志文件爆炸,全是慢SQL。
建议: 生产环境设1-2秒。
坑2:日志文件越来越大
慢查询日志一直写,磁盘满了。
解决: 用logrotate切割日志。
坑3:开启慢查询影响性能
开慢查询本身有性能损耗。
解决: 排查完就关掉,或者用低采样率。
坑4:long_query_time不生效
改了参数,但还是记录所有SQL。
原因: 连接没断开,用的还是旧参数。
解决: 重新连接MySQL。
坑5:log_output=TABLE占满系统表
把慢查询写到mysql.slow_log表,表越来越大。
解决: 定期清理:
TRUNCATE TABLE mysql.slow_log;
总结
开启三步:
SET GLOBAL slow_query_log = ONSET GLOBAL long_query_time = 2- 看日志:
mysqldumpslow -s t -t 10 slow.log
记住: 慢查询日志是优化数据库的第一步,先找到慢SQL再优化。
遇到问题加QQ23979811 协助处理
MySQL 慢查询优化实战
MySQL 慢查询优化实战
数据库慢查询是性能瓶颈的常见原因,学会优化很重要。
1. 开启慢查询日志
-- 查看是否开启
SHOW VARIABLES LIKE 'slow_query_log';
-- 开启慢查询
SET GLOBAL slow_query_log = ON;
-- 设置慢查询时间(秒)
SET GLOBAL long_query_time = 1;
2. 分析慢查询
用 EXPLAIN 分析:
EXPLAIN SELECT * FROM users WHERE name = '张三';
重点看:
- type:访问类型,ALL 是全表扫描,要优化
- key:用了哪个索引
- rows:扫描行数
3. 常见优化方法
1)加索引:
-- 加索引
ALTER TABLE users ADD INDEX idx_name(name);
*2)避免 SELECT :**
-- 不好
SELECT * FROM users;
-- 好
SELECT id, name FROM users;
3)避免在索引字段上做运算:
-- 不好
SELECT * FROM users WHERE YEAR(create_time) = 2026;
-- 好
SELECT * FROM users WHERE create_time >= '2026-01-01' AND create_time < '2027-01-01';
4)避免 LIKE 左模糊:
-- 不好(用不到索引)
SELECT * FROM users WHERE name LIKE '%张%';
-- 好
SELECT * FROM users WHERE name LIKE '张%';
4. 分页优化
-- 不好(大偏移量慢)
SELECT * FROM users LIMIT 100000, 10;
-- 好(用子查询)
SELECT * FROM users WHERE id >= (
SELECT id FROM users LIMIT 100000, 1
) LIMIT 10;
5. 常见慢查询原因
- 没加索引
- 索引失效
- 关联查询太多
- 数据量太大
- 大表分页
总结
MySQL 慢查询优化要点:
- 开启慢查询日志
- 用 EXPLAIN 分析
- 合理加索引
- 避免全表扫描
- 优化分页查询
数据库优化是个细活,多分析多测试。
MySQL慢查询开启,定位慢SQL语句方法
前言
网站越来越慢,不知道哪条 SQL 拖后腿。MySQL 自带慢查询日志功能,能把执行慢的 SQL 记录下来,方便优化。
什么是慢查询
就是执行时间超过某个阈值的 SQL 语句。默认阈值是 10 秒,太久了,一般改成 1 秒或者 2 秒。
临时开启(重启不丢)
登录 MySQL:
mysql -u root -p
开启慢查询:
-- 开启慢查询
SET GLOBAL slow_query_log = ON;
-- 设置超过1秒就记录
SET GLOBAL long_query_time = 1;
-- 查看慢查询日志位置
SHOW VARIABLES LIKE 'slow_query_log_file';
永久开启(改配置文件)
改 my.cnf:
vi /etc/my.cnf
加上:
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
重启 MySQL:
systemctl restart mysqld
慢查询日志长什么样
# Time: 2026-10-07T07:00:00.000000Z
# User@Host: root[root] @ localhost [] Id: 1234
# Query_time: 5.234567 Lock_time: 0.000123 Rows_sent: 1000 Rows_examined: 1000000
SET timestamp=1728270000;
SELECT * FROM users WHERE name LIKE '%张%';
重点看:
Query_time:执行时间Rows_examined:扫描了多少行- 最后一行就是慢 SQL 语句
分析慢查询日志
用 mysqldumpslow 工具:
# 找出最慢的10条SQL
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
# 找出返回数据最多的10条
mysqldumpslow -s r -t 10 /var/log/mysql/slow.log
参数说明:
| 参数 | 说明 |
|---|---|
-s t |
按时间排序 |
-s r |
按返回行数排序 |
-t 10 |
显示前10条 |
常见坑
坑1:没开启慢查询
不知道怎么开,或者开了忘了。
解决: 用 SHOW VARIABLES LIKE 'slow_query_log'; 确认一下。
坑2:阈值设太大
默认是 10 秒,10 秒以下的慢 SQL 都没记录到。
解决: 改成 1 秒,够用了。
坑3:日志太大占磁盘
慢查询日志一直写,磁盘满了。
解决: 配 logrotate 定期切割。
坑4:没记录没走索引的SQL
有些 SQL 虽然快,但没走索引,数据量一大就慢了。
解决: 加上这个参数,没走索引的也记录:
log_queries_not_using_indexes = 1
总结
三步开启慢查询:
- 开
slow_query_log - 设
long_query_time - 用
mysqldumpslow分析
记住: 慢查询日志是优化数据库的第一步,先开了再说。
遇到问题加QQ23979811 协助处理
MySQL 性能优化实战
MySQL 性能优化实战
数据库慢是网站性能的大问题,这篇讲实战优化方法,从几个方面下手。
1. 慢查询排查
先找到慢SQL,再优化。
开启慢查询日志:
-- 查看是否开启
SHOW VARIABLES LIKE 'slow_query_log%';
-- 开启慢查询
SET GLOBAL slow_query_log = ON;
-- 设置慢查询阈值(秒)
SET GLOBAL long_query_time = 1;
用 explain 分析:
EXPLAIN SELECT * FROM users WHERE name = '张三';
重点看:
- type:有没有用到索引(ref/const 好,ALL 全表扫描坏)
- key:实际用的索引
- rows:扫描行数
2. 索引优化
建索引原则:
- where 条件经常用的字段建索引
- 联合索引最左前缀原则
- 避免建太多索引,影响写入
查看索引:
SHOW INDEX FROM users;
建索引:
-- 普通索引
CREATE INDEX idx_name ON users(name);
-- 联合索引
CREATE INDEX idx_name_age ON users(name, age);
-- 唯一索引
CREATE UNIQUE INDEX idx_email ON users(email);
3. SQL 优化
**不要 SELECT ***
-- 坏
SELECT * FROM users WHERE id = 1;
-- 好
SELECT id, name, email FROM users WHERE id = 1;
避免 LIKE 前导模糊:
-- 坏(用不到索引)
SELECT * FROM users WHERE name LIKE '%张%';
-- 好(能用索引)
SELECT * FROM users WHERE name LIKE '张%';
大表分页优化:
-- 坏(深度分页慢)
SELECT * FROM users LIMIT 100000, 10;
-- 好(子查询先定位)
SELECT * FROM users
WHERE id >= (SELECT id FROM users LIMIT 100000, 1)
LIMIT 10;
4. 表结构优化
- 用合适的数据类型(能用 int 就别用 bigint)
- 字段尽量 NOT NULL
- 大表分表分库
5. 配置优化
my.cnf 常用配置:
# 缓冲池大小(内存的 70%)
innodb_buffer_pool_size = 1G
# 连接数
max_connections = 500
# 慢查询日志
slow_query_log = 1
long_query_time = 1
6. 总结
MySQL 优化三步走:
- 找慢SQL: 慢查询日志 + explain
- 加索引: where 条件字段
- 优化SQL: 不写 SELECT *,避免全表扫描
数据库优化不是一蹴而就,要持续监控和调整。
MySQL慢查询开启,定位慢SQL语句方法
前言
做网站开发的同学肯定遇到过这种情况:网站打开越来越慢,数据库CPU占用很高,但就是不知道哪条SQL语句拖慢了整个系统。这时候就需要用到MySQL的慢查询日志功能,把执行慢的SQL语句记录下来,然后逐个优化。
这篇文章就详细讲讲如何开启MySQL慢查询日志,以及怎么用它来定位和优化慢SQL语句。
操作步骤
1. 先查看当前慢查询日志的状态
登录MySQL之后,先看看慢查询日志有没有开启:
SHOW VARIABLES LIKE '%slow_query_log%';
执行完之后会看到类似下面的输出:
+---------------------+-----------------------------------------------+
| Variable_name | Value |
+---------------------+-----------------------------------------------+
| slow_query_log | OFF |
| slow_query_log_file | /var/lib/mysql/izuf6w7x1x2x3x4x5x6x-slow.log |
+---------------------+-----------------------------------------------+
从这里可以看到,slow_query_log 是 OFF 状态,说明慢查询日志没有开启。
2. 查看当前慢查询时间阈值
慢查询的默认时间阈值是10秒,也就是说执行时间超过10秒的SQL才会被记录。这个阈值对生产环境来说太大了,一般我们会改成1秒或者2秒。
查看当前阈值:
SHOW VARIABLES LIKE 'long_query_time';
3. 临时开启慢查询日志(重启后失效)
如果只是想临时排查问题,可以直接在MySQL命令行里开启,不需要重启服务:
-- 开启慢查询日志
SET GLOBAL slow_query_log = 'ON';
-- 设置慢查询阈值为1秒
SET GLOBAL long_query_time = 1;
这样设置之后,执行时间超过1秒的SQL语句就会被记录到慢查询日志文件里了。
4. 永久开启慢查询日志(修改配置文件)
临时开启的方式在MySQL重启之后就会失效,如果想长期开启,需要修改MySQL的配置文件。
找到MySQL的配置文件,一般是 /etc/my.cnf 或者 /etc/mysql/my.cnf,在 [mysqld] 下面添加以下配置:
[mysqld]
# 开启慢查询日志
slow_query_log = 1
# 慢查询日志文件位置
slow_query_log_file = /var/log/mysql/slow.log
# 慢查询阈值,单位秒
long_query_time = 1
# 没有用到索引的SQL也记录下来
log_queries_not_using_indexes = 1
修改完配置文件之后,重启MySQL服务:
systemctl restart mysqld
5. 查看慢查询日志内容
慢查询日志开启之后,执行慢的SQL语句就会被记录到日志文件里。我们可以直接查看日志文件:
cat /var/log/mysql/slow.log
不过慢查询日志的格式比较复杂,直接看日志文件不太直观。我们可以用 mysqldumpslow 工具来分析:
# 查看最慢的10条SQL
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
# 查看访问次数最多的10条SQL
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log
6. 使用EXPLAIN分析慢SQL
找到慢SQL之后,下一步就是分析这条SQL为什么慢。我们可以用 EXPLAIN 关键字来查看SQL的执行计划:
EXPLAIN SELECT * FROM users WHERE name = '张三';
执行完之后会输出很多字段,我们重点关注这几个:
- type:访问类型,最好是 const、eq_ref,最差是 ALL(全表扫描)
- key:实际用到的索引,如果是 NULL 说明没用到索引
- rows:扫描的行数,这个值越大越慢
- Extra:额外信息,如果看到 Using filesort 或者 Using temporary 就说明需要优化了
常见坑
坑1:开启了慢查询但日志文件里什么都没有
很多同学开启了慢查询日志,但是去看日志文件却发现什么都没有。这通常是因为以下几个原因:
- 慢查询时间阈值设置得太大了,你的SQL执行时间还没超过阈值
- 日志文件的路径不对,你看的不是正确的日志文件
- MySQL没有权限写入日志文件,需要检查文件权限
坑2:long_query_time设置了但不生效
有时候你设置了 long_query_time = 1,但是发现执行时间0.5秒的SQL也被记录下来了。这是因为当前已经建立的MySQL连接还是用的旧的阈值,需要重新连接MySQL才能生效。
坑3:慢查询日志文件太大占满磁盘
如果你的网站访问量很大,慢查询日志可能会增长得非常快,几天就把磁盘占满了。所以一定要配置日志切割,或者定期清理慢查询日志文件。
总结
MySQL慢查询日志是定位数据库性能问题的必备工具,核心就三步:
- 开启慢查询日志,设置合理的时间阈值(一般1秒)
- 用mysqldumpslow工具分析慢查询日志,找到最慢的SQL
- 用EXPLAIN分析慢SQL的执行计划,针对性优化(加索引、改写SQL等)
掌握了慢查询日志的使用方法,网站数据库性能问题就能快速定位和解决了。
遇到问题加QQ23979811 协助处理
MySQL 慢查询优化技巧
MySQL 慢查询优化实战技巧
数据库慢查询是生产环境最常见的性能问题之一。掌握慢查询优化技巧,能让系统性能提升数倍。
1. 开启慢查询日志
先开启慢查询日志,找出哪些 SQL 慢:
slow_query_log = 1
long_query_time = 1
slow_query_log_file = /var/log/mysql/slow.log
超过1秒的查询就会被记录。
2. 用 Explain 分析
慢 SQL 拿到后,用 EXPLAIN 分析执行计划:
EXPLAIN SELECT * FROM users WHERE name = '张三';
重点看:
- type:访问类型,ALL 是全表扫描,要优化
- key:实际用到的索引
- rows:扫描行数
- Extra:额外信息,Using filesort、Using temporary 要警惕
3. 加索引
最直接的优化就是加索引:
ALTER TABLE users ADD INDEX idx_name(name);
加索引原则:
- WHERE、JOIN、ORDER BY 字段优先
- 区分度高的字段效果好
- 联合索引遵循最左前缀
4. 避免 SELECT *
只查需要的字段:
-- 不好
SELECT * FROM users WHERE id = 1;
-- 好
SELECT id, name FROM users WHERE id = 1;
5. 深分页优化
LIMIT 100000, 10 很慢,因为要扫描10万行:
-- 不好
SELECT * FROM users LIMIT 100000, 10;
-- 好,用子查询
SELECT * FROM users
WHERE id >= (SELECT id FROM users LIMIT 100000, 1)
LIMIT 10;
6. 大表拆小
单表数据量超过千万行,性能会下降。可以:
- 按时间分表
- 按用户ID分库
- 归档历史数据
7. 总结
慢查询优化的核心思路:先找慢 SQL,再分析执行计划,然后加索引或改写 SQL。优化完记得对比前后效果,确保真的变快了。