前两章我们聊了 MySQL 的架构和 SQL 执行流程,现在到了“提速”的关键时刻。无论是单表查询慢得像乌龟爬,还是高并发下数据库喘不过气,性能优化都能救你于水火。这一篇,我会带你剖析 MySQL 的性能瓶颈,并给出硬核的优化招数,帮你把数据库调成“跑车”。
一、索引优化:性能的基石
索引是 MySQL 提速的头号功臣,但用不好也可能是“坑”。我们从原理到实战,拆解几个硬核技巧。
covering index(覆盖索引):不回表的神器
- 原理:查询所需的所有字段都在索引里,存储引擎不用“回表”查数据,省一次 IO。
- 例子:
SELECT name FROM users WHERE age = 20;- 如果只有
age的单列索引,查到age=20的行后,还得回表取name。 - 如果建个
(age, name)的联合索引,索引里就有name,直接返回,效率翻倍。
- 如果只有
- 硬核点:用
EXPLAIN,看Extra列有Using index就说明命中覆盖索引。
index condition pushdown(ICP,索引条件下推):过滤提速
- 原理:MySQL 5.6 引入,存储引擎在索引层就过滤掉不符合条件的数据,减少回表次数。
- 例子:
SELECT * FROM users WHERE age > 18 AND name LIKE 'T%';- 没 ICP:用
age索引查出所有age > 18的行,回表后再过滤name。 - 有 ICP:索引层先过滤
name LIKE 'T%',再回表,数据量更少。
- 没 ICP:用
- 硬核点:
EXPLAIN的Extra列有Using index condition表示启用 ICP,默认开(optimizer_switch里index_condition_pushdown=on)。
索引设计原则
- 高选择性字段优先:比如
user_id比gender更适合建索引,因为区分度高。 - 前缀索引:对长字符串(如 URL),用
CREATE INDEX idx_url ON table(url(10));只索引前 10 个字符,省空间。 - 避免冗余:
(a, b)的联合索引已经包含a,别再单独建a的索引。
- 高选择性字段优先:比如
二、配置调优:让硬件发挥极致
MySQL 的性能不只靠 SQL,还得靠配置“榨干”硬件资源。以下是几个关键参数的硬核调整。
innodb_buffer_pool_size:内存的命脉
- 作用:缓冲池缓存数据和索引,越大越能减少磁盘 IO。
- 调优:建议占物理内存的 60%-80%,比如 16GB 内存的机器,设成 10-12GB。
- 硬核点:用
SHOW STATUS LIKE 'Innodb_buffer_pool%';看命中率,Innodb_buffer_pool_reads(磁盘读)越少越好。
innodb_log_file_size:事务的加速器
- 作用:控制 redo log 文件大小,写密集场景下太小会导致频繁 checkpoint,拖慢性能。
- 调优:建议 128MB-512MB,视写负载调整,但别超缓冲池的 1/4。
- 硬核点:改之前备份,调整后重启生效,检查
SHOW VARIABLES LIKE 'innodb_log_file_size';。
tmp_table_size & max_heap_table_size:临时表优化
- 作用:控制内存临时表大小,
GROUP BY或ORDER BY时用得上。 - 调优:默认 16MB,太小会导致临时表落盘,建议调到 64MB 或更高。
- 硬核点:用
SHOW STATUS LIKE 'Created_tmp_disk_tables';看磁盘临时表数量,多了就得加内存。
- 作用:控制内存临时表大小,
三、慢查询分析:找到“罪魁祸首”
慢查询是性能杀手,怎么揪出来并干掉它?
开启慢查询日志
- 命令:
1 2 3SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1; -- 超过 1 秒记为慢查询 SET GLOBAL log_queries_not_using_indexes = 'ON'; -- 记录没用索引的查询 - 日志位置:默认在
slow_query_log_file里,可用SHOW VARIABLES LIKE 'slow_query_log_file';查看。
- 命令:
分析工具
- mysqldumpslow:自带工具,汇总慢查询并排序。
- 用法:
mysqldumpslow -t 10 /path/to/slow.log(列出 Top 10)。
- 用法:
- pt-query-digest:Percona Toolkit 的神器,生成详细报告。
- 用法:
pt-query-digest /path/to/slow.log > report.txt。
- 用法:
- 硬核点:关注
Rows_examined(扫描行数)和Query_time,找高频低效的 SQL。
- mysqldumpslow:自带工具,汇总慢查询并排序。
优化实例
- 慢 SQL:
SELECT * FROM orders WHERE order_date > '2024-01-01'; - 分析:
EXPLAIN显示type=ALL,全表扫描。 - 优化:加索引
CREATE INDEX idx_date ON orders(order_date);,再跑EXPLAIN,type变range,速度起飞。
- 慢 SQL:
四、高并发场景的硬核招数
连接池优化
- 参数:
max_connections默认 151,高并发下调到 500-1000。 - 硬核点:用
SHOW STATUS LIKE 'Threads_connected';监控,满了就报Too many connections。
- 参数:
锁粒度调整
- 问题:写多时表锁拖慢速度。
- 解决:InnoDB 默认行锁,但大事务可能升级为表锁。缩短事务,或者用
SELECT ... FOR UPDATE显式锁行。
五、实战案例
场景:一张 5000 万行的
logs表,查询SELECT * FROM logs WHERE log_time > '2025-01-01' LIMIT 10;慢得像蜗牛。- 分析:
EXPLAIN显示全表扫描,rows高达 5000 万。 - 优化:
- 加索引:
CREATE INDEX idx_time ON logs(log_time); - 改 SQL:
SELECT id, log_time FROM logs WHERE log_time > '2025-01-01' LIMIT 10;(覆盖索引)。
- 结果:查询从 10 秒降到 0.1 秒。
- 加索引:
- 分析:
场景:高并发下数据库 CPU 100%。
- 分析:
SHOW PROCESSLIST;发现大量慢查询。 - 优化:调大
innodb_buffer_pool_size,加索引,缩短事务,CPU 降到 30%。
- 分析:
结语
这一篇我们从索引、配置到慢查询,掏出了一套性能优化的硬核组合拳。掌握这些,你就能让 MySQL 在各种场景下跑得又快又稳。下一章我们会聊 高可用与分布式,看看 MySQL 怎么扛住大规模流量。
