
每天分享技术栈,开发工具等
我也曾为不懂执行计划和索引用法抓耳挠腮。今天这一篇,将带你从痛点出发,系统讲解 MySQL 性能优化与执行计划分析,让小白也能读完秒懂,迅速给业务提速、稳住数据库。
1
收集慢查询日志
在 MySQL 配置文件my.cnf中开启:
[mysqld]slow_query_log = ON -- 开启慢查询slow_query_log_file = /var/log/mysql/slow.loglong_query_time = 1 -- 记录执行时间超过1秒的SQLlog_queries_not_using_indexes = ON -- 记录未使用索引的查询2
查看监控指标 关注 TPS(每秒事务数)、QPS(每秒查询数)、InnoDB 缓冲池命中率、磁盘 IO、CPU 利用率。
3
压测对比
使用 sysbench或自建脚本,从低并发到高并发,记录响应时间、错误率,明确瓶颈是在数据库还是业务层。
小白提示:先定位再优化,避免盲目改参数导致“好像快了点”却没解决根本问题。
在客户端执行前,加上 EXPLAIN:
EXPLAIN SELECTu.id, u.name, o.order_date
FROMusers u
JOINorders o ONu.id=o.user_id
WHEREu.status='active'
ORDER BYo.order_dateDESC;
输出字段说明:
列名 | 含义 |
|---|---|
id | SELECT 查询标识,数值越大越早被执行 |
select_type | 查询类型(SIMPLE、PRIMARY、SUBQUERY 等) |
table | 正在访问的表 |
type | 连接类型(ALL、index、range、ref、eq_ref、const、system、NULL),ALL 是全表扫描,要避免 |
possible_keys | 可用索引列表 |
key | 实际使用的索引 |
rows | MySQL 估算要扫描的行数 |
Extra | 附加信息(Using where、Using filesort、Using temporary) |
注释:
type = ALL意味着全表扫描,Using filesort表示排序放在外部,需要优化索引或减少排序量。
1
选择合适列建索引:高基数、参与过滤和排序的列
2
覆盖索引:让索引包含所有查询字段,减少回表
CREATEINDEXidx_user_status_dateONorders (user_id, order_date);
-- 查询时只访问索引,即使大量数据也极快
SELECTuser_id, order_date FROMorders WHEREuser_id=123ORDER BYorder_date;
3
联合索引顺序:最左前缀原则,WHERE子句中的列应按照索引顺序最前
4
避免冗余和失效索引:不要为大量 NULL 列或低基数列建索引;防止 function(col)失效
小白示例:原始表
orders(user_id INDEX, order_date INDEX)两个单列索引,WHERE user_id=? ORDER BY order_date会先根据 user_id 找行,再排序。用联合索引NULL排序即可直接命中。
示例:原始写法
SELECT*FROMarticle WHEREid IN(SELECTarticle_id FROMtag_map WHEREtag='数据库');
重写为 JOIN
SELECTa.id, a.titleFROMarticle a
JOINtag_map t ONa.id=t.article_idANDt.tag='数据库';
参数 | 推荐设置 | 说明 |
|---|---|---|
innodb_buffer_pool_size | 服务器内存的 60%~80% | 缓冲池越大,命中率越高 |
innodb_log_file_size | 1G~4G | 影响事务提交性能 |
query_cache_type | OFF | 8.0 已移除,5.7 建议关闭,否则频繁刷新降低性能 |
tmp_table_size / max_heap_table_size | 256M~512M | 临时表溢写到磁盘会变慢 |
注意:参数修改需谨慎,线上先在测试环境验证。
小白思考:如果某张表每天新增百万行,读写分离并不能解决写入变慢,需要考虑分表或分区。
Using filesort,增加联合索引后 QPS 提升 40%vmstat、iostat、top分析。