1. 首页 > 技术教程 > 正文

MySQL 调优:缓冲区设置、慢查询优化与索引提速

MySQL 调优:缓冲区设置、慢查询优化与索引提速

MySQL 跑得慢,别急着换服务器,先从这三个方向动手。主机选这篇 Linux 教程会直接告诉你:改缓冲区参数、抓慢查询、修索引结构,90% 的性能问题都能压下来。

MySQL 调优:缓冲区设置、慢查询优化与索引提速的图片

一、缓冲区设置:别让 MySQL 饿死在内存外

缓冲区是 MySQL 的“临时仓库”,设置小了,磁盘 I/O 频繁,响应慢得像老牛拉车。

1. InnoDB 缓冲池大小

InnoDB 缓冲池(`innodb_buffer_pool_size`)是 MySQL 内存占用的主力。建议设为物理内存的 60%-80%,但别超过 80%,否则系统可能因 OOM 被 Kill。

查看当前缓冲池大小(单位字节)

SHOW VARIABLES LIKE 'innodb_buffer_pool_size';

临时调整(重启失效)

SET GLOBAL innodb_buffer_pool_size = 2147483648; # 2G

永久生效,编辑 /etc/my.cnf 或 /etc/mysql/my.cnf

[mysqld]
innodb_buffer_pool_size = 2G
innodb_buffer_pool_instances = 4 # 建议设为 1-4,减少锁竞争

老鸟叮嘱:调整后必须重启 MySQL,然后观察 `SHOW ENGINE INNODB STATUS` 中的 `Buffer pool hit rate`,如果低于 95%,说明内存不够,继续加。

2. 查询缓存别乱开

MySQL 8.0 已经移除了查询缓存(Query Cache)。如果你还在用 5.7 及以下版本,默认也建议关闭。因为写操作频繁时,缓存刷新反而拖慢性能。

检查查询缓存状态

SHOW VARIABLES LIKE 'query_cache_type';

关闭(5.7 及以下)

[mysqld]
query_cache_type = 0
query_cache_size = 0

二、慢查询优化:从日志里抓出“罪魁祸首”

慢查询日志是排查性能瓶颈的第一手资料。别问为什么,先开起来再说。

1. 开启慢查询日志

查看当前慢查询设置

SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

永久开启(my.cnf)

[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2 # 超过2秒就算慢查询
log_queries_not_using_indexes = 1 # 记录未用索引的查询

2. 分析慢查询日志

用 `mysqldumpslow` 工具快速统计:

按平均查询时间排序,显示前5条

mysqldumpslow -s t -t 5 /var/log/mysql/slow.log

输出类似:

Count: 10 Time=4.5s (45s) Lock=0.1s (1s) Rows=10000 (100000)
SELECT * FROM orders WHERE status = 'pending' ORDER BY created_at DESC;

这条查询没用到索引,而且扫描了 10000 行。接下来就要看索引怎么修。

三、索引提速:用 EXPLAIN 找到“全表扫描”的元凶

索引是 MySQL 的“目录”,没索引就等于翻书一页页找。

1. 用 EXPLAIN 诊断查询计划

sql
EXPLAIN SELECT * FROM orders WHERE status = 'pending' AND created_at > '2024-01-01';

重点关注:

• `type`:如果是 `ALL`,说明全表扫描,必须加索引。

• `rows`:扫描行数,越小越好。

• `Extra`:出现 `Using filesort` 或 `Using temporary`,说明排序或分组没用到索引。

2. 添加复合索引

根据慢查询日志中的 SQL,建一个复合索引:

sql
— 把 where 条件中的字段放前面,排序字段放后面
ALTER TABLE orders ADD INDEX idx_status_created (status, created_at);

老鸟叮嘱:复合索引遵循“最左前缀原则”。比如 `(status, created_at)` 能加速 `WHERE status = 'pending'` 和 `WHERE status = 'pending' ORDER BY created_at`,但不能加速 `WHERE created_at > '2024-01-01'`。

3. 索引别建太多

每张表的索引数量建议控制在 5 个以内。索引越多,写入越慢。定期用 `SHOW INDEX FROM table_name` 检查重复或冗余索引。

四、常见排障

1. 改了 my.cnf 没生效

确认 MySQL 读取的配置文件路径

mysql –help | grep 'Default options' -A 1

2. 慢查询日志没内容

检查文件权限

ls -l /var/log/mysql/slow.log

临时触发一条慢查询测试

SELECT SLEEP(3);

3. 索引明明有,EXPLAIN 还是全表扫描

原因:表数据量太小(几百行),MySQL 认为全表扫描更快。或者查询中使用了函数、隐式类型转换,导致索引失效。

sql
— 错误示例:status 是字符串,但查询用了数字
SELECT * FROM orders WHERE status = 1;
— 正确写法
SELECT * FROM orders WHERE status = '1';

五、老鸟叮嘱

千万不要在生产库上直接改 `innodb_buffer_pool_size` 为过大的值,比如 32G 内存的机器,你设成 30G,系统直接 OOM。先看 `free -h` 确认空闲内存,再逐步上调。

FAQ

Q:MySQL 缓冲区设置多大合适?

A:InnoDB 缓冲池设为物理内存的 60%-80%,但留出 20% 给操作系统和其他进程。用 `SHOW ENGINE INNODB STATUS` 观察 `Buffer pool hit rate`,低于 95% 就加内存。

Q:慢查询日志文件太大怎么办?

A:设置 `long_query_time` 为 2-5 秒,避免记录太多小查询。也可以定期用 `mysqldumpslow` 汇总后清空日志,或者用 `pt-query-digest` 工具分析。

Q:索引越多查询越快吗?

A:不是。索引会拖慢 INSERT、UPDATE、DELETE 操作。一张表建议不超过 5 个索引,定期用 `SHOW INDEX` 检查冗余索引。

Q:EXPLAIN 中 type 字段出现 ALL 是什么意思?

A:ALL 表示全表扫描,是性能最差的类型。必须加索引。理想情况下是 const、eq_ref、ref、range。

Q:修改 my.cnf 后 MySQL 启动报错怎么办?

A:先注释掉刚加的配置,重启确认能启动。然后逐步排查:检查参数名是否写错(如 `innodb_buffer_pool_size` 拼成 `innodb_buffer_pool`),或者值超出限制。

Q:MySQL 8.0 和 5.7 在调优上有什么区别?

A:8.0 移除了查询缓存,但优化了 InnoDB 性能。8.0 的 `innodb_buffer_pool_size` 可以动态调整(需设置 `innodb_buffer_pool_chunk_size`),但建议还是重启生效。

转载请注明出处:https://www.zhujixuan.com/jishujiaocheng/9540.html 商家投稿邮箱:zhujixuanblog@qq.com