MySQL 如何进行 SQL 调优?

MySQL SQL 调优是一个系统化工程,核心流程如下:

MySQL 如何进行 SQL 调优?

MySQL 如何进行 SQL 调优?

上图展示了 SQL 调优的完整流程。整体分为四个阶段:

  • 阶段一(开启监控):通过配置 slow_query_log=ON 开启慢查询日志,设置 long_query_time 阈值(默认 10 秒,生产建议 1-3 秒),为后续分析提供数据基础。
  • 阶段二(定位问题):使用 mysqldumpslow 工具分析慢查询日志,按执行时间、执行次数排序,快速锁定最需要优化的 SQL。
  • 阶段三(分析原因):对目标 SQL 执行 EXPLAIN 查看执行计划,重点关注 typekeyrowsExtra 字段,判断是否走索引、扫描行数是否合理。
  • 阶段四(优化验证):根据分析结果进行索引优化、SQL 改写、表结构调整,然后再次执行 EXPLAIN 验证效果。

一句话总结:调优 = 慢日志定位 + EXPLAIN 分析 + 索引优化 + SQL 改写。

深度解析

一、定位慢 SQL:慢查询日志

首先需要开启慢查询日志,记录执行时间超过阈值的 SQL:

-- 查看慢查询日志配置
SHOW VARIABLES LIKE '%slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

-- 开启慢查询日志(临时生效)
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2;  -- 超过 2 秒记录
SET GLOBAL log_queries_not_using_indexes = 'ON';  -- 记录未走索引的 SQL

-- 永久生效需修改 my.cnf
[mysqld]
slow_query_log = 1
long_query_time = 2
slow_query_log_file = /var/log/mysql/slow.log

使用 mysqldumpslow 工具分析慢日志:

# 按查询时间排序,显示前 10 条
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

# 按查询次数排序
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log

二、分析执行计划:EXPLAIN 详解

使用 EXPLAIN 或 EXPLAIN ANALYZE(MySQL 8.0+)查看 SQL 执行计划:

EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 'PAID';

关键字段解读

字段 含义 关注点
type 访问类型(效率从高到低) system > const > eq_ref > ref > range > index > ALL(全表扫描,需优化)
key 实际使用的索引 是否命中预期索引
key_len 使用的索引长度 越短越好,判断联合索引使用情况
rows 预估扫描行数 越少越好
Extra 额外信息 Using filesort(文件排序)、Using temporary(临时表)需要关注

type 类型效率对比

MySQL 如何进行 SQL 调优?

MySQL 如何进行 SQL 调优?

上图展示了 EXPLAIN 中 type 字段的访问类型,从左到右效率递减:

  • system/const:最高效,主键或唯一索引查询,最多返回一行数据。
  • eq_ref:唯一索引关联查询,每个索引键值对应一行。
  • ref:非唯一索引查询,可能返回多行。
  • range:索引范围扫描,如 BETWEEN><IN 等操作。
  • index:遍历整个索引树,比 ALL 稍好(索引比数据文件小)。
  • ALL:全表扫描,性能最差,需要重点关注优化

三、索引优化:最常见的调优手段

1. 索引创建原则

-- 为高频查询条件创建索引
CREATE INDEX idx_user_status ON orders(user_id, status);

-- 联合索引遵循"最左前缀原则"
-- 索引 (a, b, c) 可支持:a | a,b | a,b,c 的查询
-- 无法支持:b | c | b,c 的查询(缺少最左列)

2. 索引失效场景

MySQL 如何进行 SQL 调优?

MySQL 如何进行 SQL 调优?

上图总结了索引失效的六大常见场景。每个场景都需要特别注意:

  • 函数/计算:索引列经过函数处理后,B+ 树的有序性被破坏,无法利用索引。
  • 隐式转换:MySQL 会将字符串转数字进行比较,相当于对列做了函数操作。
  • LIKE 前缀通配%xxx 无法利用 B+ 树的有序性,只能全扫描。
  • OR 条件:只要有一个条件列没有索引,整体就会退化为全表扫描。
  • 最左前缀:联合索引按照定义顺序构建,跳过前面的列无法利用索引。
  • 否定条件:优化器可能认为返回数据量过大,直接全表扫描更高效。

四、SQL 语句优化技巧

1. 避免 SELECT *

-- ❌ 不推荐:查询所有列,增加 IO 和网络开销
SELECT * FROM orders WHERE user_id = 100;

-- ✅ 推荐:只查询需要的列
SELECT order_id, amount, status FROM orders WHERE user_id = 100;

2. 优化分页查询

-- ❌ 深分页性能差:需要扫描前 100000 条
SELECT * FROM orders LIMIT 100000, 10;

-- ✅ 方案一:基于游标分页(需要连续 ID)
SELECT * FROM orders WHERE id > 100000 LIMIT 10;

-- ✅ 方案二:延迟关联(先查 ID,再关联)
SELECT o.* FROM orders o
INNER JOIN (SELECT id FROM orders LIMIT 100000, 10) t
ON o.id = t.id;

3. 优化 COUNT 查询

-- ❌ COUNT(*) 扫描全表
SELECT COUNT(*) FROM orders WHERE status = 'PAID';

-- ✅ 维护计数表(适合高频统计场景)
CREATE TABLE order_stats (status VARCHAR(20), count INT);
-- 业务变更时同步更新计数

4. 优化 ORDER BY

-- ❌ filesort:排序字段未走索引
SELECT * FROM orders WHERE user_id = 100 ORDER BY create_time;

-- ✅ 创建联合索引,覆盖 WHERE + ORDER BY
CREATE INDEX idx_user_time ON orders(user_id, create_time);

五、表结构优化

1. 选择合适的数据类型

场景 推荐类型 原因
主键 ID BIGINT 或 BIGINT UNSIGNED 避免溢出,预留空间
状态字段 TINYINT 1 字节存储,配合枚举含义
字符串 VARCHAR(N) 变长存储,N 不宜过大
时间 DATETIME 或 TIMESTAMP 根据时区需求选择
大文本 独立表 + 外键 避免影响主表性能

2. 适度反范式设计

-- 范式设计:订单表只存 user_id,查询时 JOIN 用户表
SELECT o.*, u.name FROM orders o JOIN users u ON o.user_id = u.id;

-- 反范式设计:订单表冗余 user_name(适合读多写少场景)
-- 优点:减少 JOIN,提升查询性能
-- 缺点:用户改名需同步更新订单表

六、高级调优工具

1. SHOW PROFILE(查询性能剖析)

-- 开启 profiling
SET profiling = 1;

-- 执行 SQL
SELECT * FROM orders WHERE user_id = 100;

-- 查看性能详情
SHOW PROFILE;
SHOW PROFILE FOR QUERY 1;  -- 查看具体 SQL 的各阶段耗时

2. Performance Schema(MySQL 5.7+)

-- 查看哪些 SQL 执行时间最长
SELECT * FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC LIMIT 10;

3. EXPLAIN ANALYZE(MySQL 8.0+)

-- 真实执行 SQL 并显示各步骤实际耗时
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 100;
上一篇 Navicat Premium 17.3.4 专业版下载及安装教程
下一篇 vmware workstation pro v25中文免费版下载及安装使用教程

站点性能

运行正常
实时心跳0 ms
页面加载
0
SQL 查询
0
服务端响应
0 ms
峰值内存
0 MB
阿陶学长

阿陶学长管理员

专注于分享最有价值的互联网干货

本月创作热力图

最新评论
暂无评论
AeroCore图片