MySQL 慢查询日志及优化

一、简介

MySQL 慢查询日志是定位数据库性能瓶颈的核心工具,主要用于追踪执行效率低下的 SQL 语句。通过慢查询日志,可以查找出哪些查询语句的执行效率低,以便进行优化。慢查询日志默认不开启。

二、作用

慢查询日志用于记录执行时间超过设定阈值的 SQL 语句,帮助开发者或 DBA 发现 "拖慢" 数据库的低效查询。其核心价值在于:

  • 精准定位耗时较长的 SQL(如全表扫描、复杂关联查询等);

  • 分析查询的执行频率、锁等待时间、扫描行数等关键指标;

  • 为 SQL 优化、索引调整、表结构设计提供数据依据。

三、关键配置参数及开启方式

1、关键配置参数

参数名 含义 默认值
slow_query_log 是否开启慢查询日志(1开启,0关闭) 0
slow_query_log_file 慢查询日志文件路径 取决于系统,如 /var/log/mysql/slow.log
long_query_time 慢查询阈值(单位:秒),执行时间 ≥ 该值 的 SQL 会被记录 10
log_queries_not_using_indexes 是否记录未使用索引或是全表扫描的查询(即使执行时间未超过 long_query_time) 0
log_slow_rate_limit 查询多少次才记录,MariaDB 特有配置项 1

2、临时开启

通过 SET GLOBAL 命令修改参数,当前会话生效,重启失效

sql 复制代码
-- 开启慢查询日志
SET GLOBAL slow_query_log = 1;

-- 设置日志文件路径(需提前创建目录并授权)
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';

-- 设置慢查询阈值(如 10 秒,支持小数,如 0.5 表示 500 毫秒)
SET GLOBAL long_query_time = 10;

-- 记录未使用索引的查询(可选,用于发现索引缺失问题)
SET GLOBAL log_queries_not_using_indexes = 1;

3、永久开启

修改 MySQL 配置文件(通常为 /etc/my.cnf 或 /etc/mysql/my.cnf),在 mysqld 段添加相关配置参数

bash 复制代码
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 10  # 阈值 10 秒
log_queries_not_using_indexes = 1  # 记录未用索引的查询

修改后重启 MySQL 服务生效

四、慢查询日志分析

1、模拟慢查询

临时开启慢查询日志,设置阈值为1秒,设置日志输出为 /var/log/mysql/slow.log

执行慢查询动作,生成日志

查看日志

2、日志关键字段解析

  • Query_time:SQL 执行时间(秒),此处为 3 秒,超过阈值 1 秒;

  • Lock_time:锁等待时间(秒),此处 0 秒,若过大可能存在锁竞争;

  • Rows_sent:返回给客户端的行数(1行);

  • Rows_examined:扫描的行数(1 行)

3、定位问题的步骤

筛选关键慢查询:优先关注 Query_time 大、执行频率高的 SQL(可通过 mysqldumpslow 工具统计,如 mysqldumpslow -s t -t 10 /var/log/mysql/slow.log 按时间取前 10 条)。

分析执行计划:对慢查询使用 EXPLAIN 工具查看执行计划,重点关注:

  • type:访问类型(ALL 表示全表扫描,性能最差;ref/range 表示使用索引,较优);

  • key:实际使用的索引(NULL 表示未使用索引);

  • rows:预估扫描行数(值越大,效率越低);

  • Extra:额外信息(如 Using filesort 表示需要排序,Using temporary 表示使用临时表,均需优化)。

定位根因:结合执行计划判断问题类型,例如:

  • 若 type=ALL 且 key=NULL:未创建合适的索引;

  • 若 rows 远大于 Rows_sent:索引过滤性差(如区分度低的字段);

  • 若 Lock_time 大:存在行锁 / 表锁竞争(如高并发更新同一行)。

五、常见的慢查询优化

针对慢查询日志定位的问题,常见优化手段可分为索引优化、SQL 语句优化、表结构优化和配置优化四类:

1、索引优化

  • 添加合适的索引:为查询条件(WHERE)、关联字段(JOIN ON)、排序字段(ORDER BY)创建索引;

  • 避免索引失效:不使用函数或表达式处理索引字段(如 WHERE SUBSTR(phone,1,3)='138' 会导致 phone 索引失效);避免 !=、NOT IN、IS NOT NULL 等操作(索引难以高效过滤);

  • 避免隐式类型转换:字符串查询加引号(如 WHERE name='123' 而非 WHERE name=123);

  • 删除冗余索引:同一字段的重复索引会增加写入开销。

2、SQL 语句优化

  • 避免 SELECT *:只查询需要的字段,减少 IO 开销;

  • 拆分复杂查询:将一次性执行的大查询拆分为多个小查询(如分页查询用 LIMIT 限制行数,避免全表扫描后过滤);

  • 优化关联查询:JOIN 表数量控制在 3 张以内,关联字段必须建索引,避免 LEFT JOIN 时右表条件导致全表扫描;避免笛卡尔积;

  • 替换子查询:子查询可能产生临时表,改用 JOIN 优化(如 SELECT * FROM t1 WHERE id IN (SELECT id FROM t2) 改为 SELECT t1.* FROM t1 JOIN t2 ON t1.id = t2.id)。

3、表结构优化

  • 分表分库:大表(千万级以上)按时间(如订单表按月份分表)或哈希(如用户表按 user_id 分表)拆分,减少单表数据量。

  • 选择合适的数据类型:如用 INT 代替 VARCHAR 存储数字,DATE/DATETIME 代替字符串存储日期,减少存储空间和比较开销。

  • 避免大字段:TEXT/BLOB 等大字段单独存表,避免查询时不必要的 IO 消耗。

4、配置优化

  • 调整缓存:增大 innodb_buffer_pool_size(InnoDB 缓存池,建议占物理内存的 50%-70%),减少磁盘 IO;

  • 优化连接:调整 max_connections 避免连接数不足,wait_timeout 释放闲置连接;

  • 日志优化:非必要时关闭 log_queries_not_using_indexes(避免日志过大),定期轮转慢查询日志。

相关推荐
Fleshy数模8 小时前
CentOS7 安装配置 MySQL5.7 完整教程(本地虚拟机学习版)
linux·mysql·centos
az44yao9 小时前
mysql 创建事件 每天17点执行一个存储过程
mysql
秦老师Q10 小时前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
橘子1311 小时前
MySQL用户管理(十三)
数据库·mysql
Dxy123931021611 小时前
MySQL如何加唯一索引
android·数据库·mysql
我真的是大笨蛋11 小时前
深度解析InnoDB如何保障Buffer与磁盘数据一致性
java·数据库·sql·mysql·性能优化
怣5011 小时前
MySQL数据检索入门:从零开始学SELECT查询
数据库·mysql
人道领域12 小时前
javaWeb从入门到进阶(SpringBoot事务管理及AOP)
java·数据库·mysql
千寻技术帮13 小时前
10404_基于Web的校园网络安全防御系统
网络·mysql·安全·web安全·springboot
spencer_tseng14 小时前
MySQL table backup
mysql