当前位置: 首页 > news >正文

mysql慢查询sql

        在 MySQL 中,慢查询 SQL指的是执行时间超过预设阈值(通常由long_query_time参数定义)的 SQL 语句。这类 SQL 会消耗大量数据库资源(如 CPU、IO、内存),是导致数据库性能下降的常见原因。以下从慢查询的识别、分析、常见原因及优化方法展开详细说明。

一、如何识别慢查询?—— 开启慢查询日志

要监控慢查询,首先需要开启 MySQL 的慢查询日志(slow query log),它会记录所有执行时间超过long_query_time的 SQL 语句。

1. 慢查询日志核心配置参数
参数名作用说明默认值
slow_query_log是否开启慢查询日志(ON开启,OFF关闭)OFF
slow_query_log_file慢查询日志存储路径(需确保 MySQL 有写入权限)取决于系统
long_query_time慢查询阈值(单位:秒),执行时间超过此值的 SQL 会被记录10
log_queries_not_using_indexes是否记录未使用索引的 SQL(即使执行时间未超过long_query_timeOFF
 配置慢查询日志的方法
(1)通过配置文件永久生效(推荐)

        修改 MySQL 配置文件(如my.cnfmy.ini),在[mysqld]节点下添加以下配置:

[mysqld]
slow_query_log = ON                   # 开启慢查询日志
slow_query_log_file = /var/log/mysql/mysql-slow.log  # 日志路径
long_query_time = 1                   # 阈值设为1秒(根据业务调整)
log_queries_not_using_indexes = ON    # 记录未用索引的SQL

配置后重启 MySQL 服务使生效:

# CentOS/RHEL
systemctl restart mysqld
# Ubuntu/Debian
systemctl restart mysql
(2)通过 SQL 动态生效(临时,重启失效)
-- 开启慢查询日志
SET GLOBAL slow_query_log = ON;
-- 设置日志路径(需MySQL有权限写入)
SET GLOBAL slow_query_log_file = '/var/log/mysql/mysql-slow.log';
-- 设置阈值为1秒
SET GLOBAL long_query_time = 1;
-- 记录未使用索引的SQL
SET GLOBAL log_queries_not_using_indexes = ON;

二、如何分析慢查询日志?

        慢查询日志生成后,需通过工具分析关键信息(如执行频率最高、耗时最长的 SQL)。

1. 自带工具:mysqldumpslow

        MySQL 内置的mysqldumpslow工具可汇总慢查询日志,按不同维度排序(如执行时间、次数),适合快速定位问题 SQL。

常用参数

  • -s:排序方式(t按时间,l按锁等待,r按返回行数,c按执行次数);
  • -t N:显示前 N 条结果;
  • -g:通过正则匹配 SQL(不区分大小写)。

示例

# 查看执行时间最长的前10条SQL
mysqldumpslow -s t -t 10 /var/log/mysql/mysql-slow.log# 查看执行次数最多的前10条SQL
mysqldumpslow -s c -t 10 /var/log/mysql/mysql-slow.log# 查看包含"SELECT"且执行时间最长的SQL
mysqldumpslow -s t -t 5 -g "select" /var/log/mysql/mysql-slow.log
2. 更强大的工具:pt-query-digest

        Percona Toolkit 中的pt-query-digest功能更全面,可分析 SQL 执行频率、平均耗时、锁等待等,还能识别重复 SQL(如参数不同但结构相同的语句)。

安装

bash

# CentOS/RHEL
yum install percona-toolkit
# Ubuntu/Debian
apt install percona-toolkit

示例

bash

# 分析慢查询日志并输出详细报告
pt-query-digest /var/log/mysql/mysql-slow.log

        报告中会标注 “总耗时占比最高”“执行次数最多” 的 SQL,是优化的优先目标。

3. 实时监控:Performance Schemasys

        若需实时查看慢查询(无需等待日志写入),可通过Performance Schema(性能字典)和sys库(简化性能查询)实现。

示例:查看当前正在执行的慢查询:

sql

-- 利用sys库的processlist视图,筛选执行时间超过1秒的SQL
SELECT * FROM sys.processlist WHERE time > 1 AND state != 'Sleep';

三、慢查询 SQL 的常见原因

        慢查询的本质是 “低效的执行计划”,常见原因包括:

1. 索引问题(最常见)
  • 无索引:SQL 扫描全表(type: ALL),数据量大时耗时极长;
  • 索引失效:如索引列被函数 / 运算操作(WHERE YEAR(create_time)=2023)、隐式类型转换(WHERE phone = 13800138000,若phone是字符串类型)、使用NOT IN/!=等导致索引失效;
  • 索引不合理:如索引选择性低(如 “性别” 列建索引)、重复索引(同一列建多个索引)。
2. SQL 结构不合理
  • 全表扫描SELECT *读取无关字段,增加 IO 和内存消耗;
  • 子查询效率低:多层嵌套子查询可能导致重复扫描,不如JOIN高效;
  • 分页偏移量大LIMIT 100000, 10需扫描前 100010 条数据,偏移量越大越慢;
  • 大表JOIN:未优化的JOIN可能导致笛卡尔积,尤其大表关联大表时。
3. 数据量与表设计问题
  • 表数据量过大:单表千万级以上未分表,扫描成本高;
  • 锁竞争:SQL 涉及行锁 / 表锁,长时间持有锁导致其他请求阻塞。

四、慢查询 SQL 的优化方法

针对上述原因,可通过以下方法优化:

1. 优化索引
  • 添加合适的索引:为WHEREJOINORDER BY后的字段建索引(如CREATE INDEX idx_user_name ON users(name));
  • 避免索引失效
    • 不对索引列做函数 / 运算(如WHERE create_time >= '2023-01-01'代替WHERE YEAR(create_time)=2023);
    • 避免隐式转换(如WHERE phone = '13800138000',确保参数类型与字段一致);
  • 删除冗余索引:通过sys.schema_unused_indexes查看未使用的索引并删除。
2. 优化 SQL 结构
  • 避免SELECT *:只查询需要的字段(如SELECT id, name FROM users);
  • JOIN替代子查询:子查询可能重复执行,JOIN更高效(如SELECT a.id FROM a JOIN b ON a.b_id = b.id代替SELECT id FROM a WHERE b_id IN (SELECT id FROM b));
  • 优化分页查询:偏移量过大时,用 “条件定位” 代替OFFSET(如SELECT * FROM users WHERE id > 100000 LIMIT 10,需id有索引);
  • 拆分大JOIN:将大表JOIN拆分为多次查询,或用中间表暂存结果。
3. 分析执行计划:EXPLAIN

  EXPLAIN可查看 SQL 的执行计划,判断是否使用索引、扫描行数等,是优化的核心工具。

示例:分析一条查询的执行计划:

sql

EXPLAIN SELECT id, name FROM users WHERE age > 30 AND status = 1;

关键输出字段

  • type:访问类型(ALL全表扫描,ref索引查找,range范围扫描,const常量查找,性能从差到好);
  • key:实际使用的索引(NULL表示未用索引);
  • rows:估计扫描的行数(值越小越好);
  • Extra:额外信息(如Using filesort表示需要排序,Using temporary表示用临时表,均需优化)。
4. 其他优化
  • 分表分库:大表按时间 / ID 分表(如users_2023users_2024),降低单表数据量;
  • 批量操作:用INSERT INTO ... VALUES (...), (...)代替循环单条插入;
  • 调整数据库参数:如增大join_buffer_sizeJOIN缓存)、sort_buffer_size(排序缓存)等(需结合服务器资源)。

五、注意事项

  • 阈值合理设置long_query_time不宜过大(如默认 10 秒可能放过很多问题 SQL),建议根据业务设置为 0.5-2 秒;
  • 日志管理:慢查询日志会占用磁盘空间,需定期轮转(如用logrotate)或清理;
  • 开发规范:上线前用EXPLAIN检查 SQL,禁止全表扫描、复杂子查询等高危操作。
http://www.dtcms.com/a/326057.html

相关文章:

  • 分裂的王国——进程间通信
  • GeoScene 空间大数据产品使用入门(1)应用场景与基本流程
  • 【接口自动化】-7- 热加载和日志封装
  • .NET Core MVC中CSHTML
  • 【测试】BDD与TDD在软件测试中的对比?
  • AI蛋白质设计学习主线
  • 【智能的起源】人类如何模仿,简单的“刺激-反应”机制 智能的核心不是记忆,而是发现规律并能迁移到新场景。 最原始的智能:没有思考,只有简单条件反射
  • 首涂模板第45套主题2.0修正版苹果CMS模板奇艺主题二开源码
  • 解决 VS Code 右键菜单丢失问题
  • calamine读取xlsx文件的方法比较
  • Spring Boot 2.0 升级至 3.5 JDK 1.8 升级至 17 全面指南
  • 计算机视觉CS231n学习(7)
  • 【Altium designer】解决报错“Access violation at address...“
  • 【代码随想录day 17】 力扣 617.合并二叉树
  • python魔法方法__str__()介绍
  • 【Lua】题目小练9
  • 从零构建自定义Spring Boot Starter:打造你的专属开箱即用组件
  • 爬虫与数据分析入门:从中国大学排名爬取到数据可视化全流程
  • Go语言构建高性能AI分析网关:原理与实战
  • 设计模式笔记_结构型_组合模式
  • React(四):事件总线、setState的细节、PureComponent、ref
  • Jenkins 搭建鸿蒙打包
  • 【k8s】k8s中的几个概念性问题
  • day48 力扣739. 每日温度 力扣496.下一个更大元素 I 力扣503.下一个更大元素II
  • 轻量级解决方案:如何高效处理Word转PDF?
  • k8s的calico是什么作用,举例一下
  • 【2025最新版】PDF24 Creator,PDF编辑,合并分割,格式转换全能工具箱,本地离线版本,完全免费!
  • 【C语言强化训练16天】--从基础到进阶的蜕变之旅:Day1
  • 【12-激活函数】
  • 【PRML】分类