Linux上慢SQL查询与优化

[复制链接]
发表于 2026-10-4 19:22:29 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

线上数据库变慢,最先该看的往往不是“哪条语句慢”,而是“哪些语句在大量重复消耗资源”。MySQL 的慢查询日志日志就是干这个的。本文把从开通慢日志日志、筛选归类、用工具分析、读执行计划,到具体优化手段的完整链路讲一遍,顺带说明怎么跟踪优化效果,避免改完没有回执。

一、先确认慢查询日志日志开了没

没开慢日志就谈优化,等于闭着眼走路。用下面两条命令看状态和文件位置:

SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'slow_query_log_file';

# 看当前的慢查询阈值
SHOW VARIABLES LIKE 'long_query_time';

没开启的话,在配置文件(/etc/my.cnf 或 /etc/my.ini)里加上,然后重启数据库:

[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 1
log_queries_not_using_indexes = 1

long_query_time 的单位是秒,1 表示超过 1 秒记入。这个值不是越小越好:太小会让日志暴涨、磁盘先撑不住,一般从 1 秒起步,跑稳了再往下压。开了 log_queries_not_using_indexes 可以把没走索引的查询也捞出来,适合初期摸底。

二、初步筛选和分类

日志里通常成百上千条,先按两个维度归类:

  • 按耗时排序:把执行时间最长的挑出来,它们对整体性能影响最大。
  • 按出现频率分类:有的语句每次都很快但一天跑十万次,累积起来照样拖垮库;有的语句执行一次几秒但一天只跑两次,影响有限。

判断优先级有个简单公式:总耗时 = 单次耗时 × 执行次数,先处理总耗时排前面的那一批。

三、用工具做批量分析

1. mysqldumpslow

MySQL 自带的分析工具,不用额外装。常用参数:

  • -s:指定排序方式。c 按出现次数、t 按总时间、l 按查询时间、r 按返回记录数;前面加大写 a 表示倒序,比如 -sc 就是按次数降序。
  • -t:返回前几条,比如 -t 10 取前 10。
  • -g:跟一个正则做过滤,忽略大小写。
# 按查询时间排序的耗时最长前 10 条
mysqldumpslow -s t -t 10 /var/log/mysql/mysql-slow.log

# 按出现次数排序的前 10 条
mysqldumpslow -s c -t 10 /var/log/mysql/mysql-slow.log

# 只看包含 JOIN 语句的部分
mysqldumpslow -s t -t 10 -g "join" /var/log/mysql/mysql-slow.log

2. pt-query-digest

Percona Toolkit 里的工具,比 mysqldumpslow 强在能给出更完整的统计(响应分布、本次/上次对比、模式归一化后的模板),适合做深度分析。常用参数:

  • --create-review-table:配合 --review 把结果落到表里,便于多人协作标记
  • --create-history-table:配合 --history 把结果落到表里,便于做趋势对比
  • --filter:按指定字符串先过滤再分析
  • --limit:限制输出条数,默认 20,即输出最慢的 20 条
pt-query-digest /var/log/mysql/mysql-slow.log > slow_report.txt

安装方式:yum install -y percona-toolkit 或到 Percona 官方源装对应版本。没有的话也能用 Docker 跑。

四、回到 SQL 本身:读执行计划

拿到具体语句后,用 EXPLAIN(MySQL 8 里也可以用 EXPLAIN ANALYZE 拿到真实耗时)看它到底怎么执行。重点关注这几列:

字段看什么
type连接类型,性能由好到差大致是 system > const > eq_ref > ref > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > all
rowsMySQL 估算要扫描的行数,InnoDB 下是估计值
filtered百分比,表示经过条件过滤后剩余记录的比例
key实际用到的索引,要跟 possible_keys 一起看,确认是否用上了预期的索引
extra额外信息,见下表

extra 里最需要警惕的几个:

  • Using filesort:排序没走索引,数据在磁盘上排,数据量大时很慢
  • Using temporary:用了临时表,性能较差,是重点优化对象
  • Using index:覆盖索引,不需要回表,是好事
  • Using where:用了 WHERE 条件过滤
  • Using index condition:MySQL 5.6 之后的索引下推,在存储引擎层先过滤,减少回表

五、索引与查询逻辑的检查点

  • 索引有没有真正用上:查询条件里出现频率高的字段建索引;选择性低的字段(比如只有两个取值的状态字段)单独建索引意义不大,可以建联合索引放在后面。
  • 联合索引的顺序:遵循最左前缀。建了 (a, b, c),where b = ? 这种用不上。
  • 隐式类型转换:字段是字符串,条件里写数字,索引会失效。这是最常见的“明明有索引却全表扫”。
  • 子查询与 OR:不必要的子查询、复杂连接、过多的 OR 条件都值得重写。复杂 OR 有时改成 UNION 或者先落到临时表处理更划算。
  • 数据量与分布:即使有索引,单表上千万且查询条件无选择性时依然慢。考虑分区、分表或归档历史数据;数据里某个值出现比例特别高(例如一个状态占 90%),索引选择性就会变差。

六、结合系统资源和性能指标一起看

慢 SQL 有时不只是 SQL 的问题:

  • 系统资源:用 top、vmstat、iostat 看 CPU、内存、磁盘 I/O。若磁盘 iowait 长期偏高,慢的是 IO 不是语句。
  • 连接数:连接数过多会消耗资源,还会让排队延迟变高。看 SHOW STATUS LIKE 'Threads_connected' 与 max_connections 的比值。
  • 事务处理:长事务、频繁回滚会持有锁和 undo,影响并发。查 information_schema.innodb_trx 看当前跑着的事务。

七、通用的优化手段

  • 用在条件里频繁查询的列上建索引,减少扫描行数。
  • 避免把 % 开头放在 like 前面(LIKE '%abc'),这类无法走索引,考虑倒排或全文索引。
  • 能不用子查询就改成 JOIN,必要时拆成应用层多次查询。
  • 字段选够用的数据类型,别都用 varchar(255),更紧凑的类型在 InnoDB 下对索引和 IO 都友好。
  • 别写 SELECT *,只取需要的列,能减少传输量,也更容易覆盖索引。
  • 只取需要的行数,用 LIMIT 限制结果集。
  • 每条改动后用 EXPLAIN 复核一遍,确认 type 和 key 符合预期。
  • 高频重复查询考虑缓存(应用层缓存或查询缓存策略),减少对数据库的重复访问。

八、记录与跟踪,别让优化停在纸面

  • 建文档:把 SQL 原文、执行时间、发现的问题、优化建议、改动时间记下来,方便后续复盘和团队交接。
  • 再跑一次慢日志:优化完成后重新采集一段时间,确认目标语句从慢日志里消失了、或者耗时明显下降。
  • 没效果就重新分析:优化后仍然出现或没有提升,通常是方向选错了(比如瓶颈在 IO 或锁,不在语句),回到执行计划和资源指标重新定位。

九、总结

慢 SQL 优化是一条可重复的流水线:开日志 → 筛出总耗时最高的语句 → 用 EXPLAIN 定位执行计划 → 补索引或改写法 → 观察资源与锁 → 记录并回测。真正决定效果的是“是否回测”这一环,很多优化停留在改了就算完,上线后没有指标支撑,下次出问题还是从零开始。把每次优化的语句、耗时、执行计划和最终结果记成条目,积累几次之后,这类问题的定位速度会有量级提升。

qidao123.com企服评测-应用市场 编辑提示

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表