【老铁必看】MySQL性能优化究极指南!从误区到实操,带你从青铜到王者!(内含大量翻车案例)
一、MySQL性能优化の大型打脸现场(误区篇)
1. 硬件能解决一切?Naive!
- 土豪老哥A怒砸10W买顶配服务器,结果表设计稀烂,全表扫描照样卡成PPT(真实案例:某电商用varchar存时间字段导致索引失效)
- 磁盘再快也顶不住你写select * from 百万级表啊铁子!
2. 数据库性能好就万事大吉?
- 程序猿老哥B用Redis缓存了热点数据,结果N+1查询把DB干趴(奥利给?)
- 连JDBC连接池都不配,高并发直接GG思密达
3. 索引是万金油?
- 索引狂魔老哥C给所有字段建索引,结果写操作比蜗牛还慢(某社交App血泪教训)
- 最左前缀原则都不懂?建了联合索引照样用不上(where条件顺序搞反直接凉凉)
二、SQL执行の底层黑科技(原理篇)
1. 查询执行流程(划重点!)
客户端 → 连接器(八阿哥:Too many connections警告)→ 分析器(语法纠错王)→ 优化器(索引选择困难症)→ 执行器(真正干活的)→ 存储引擎
2. 更新流程の灵魂双日志(redolog vs binlog)
- redolog:InnoDB的后悔药(物理日志,循环写)
- binlog:Server层的时光机(逻辑日志,追加写)
- 两阶段提交:先写redolog prepare → 写binlog → redolog commit(防止数据精分)
三、索引の祖传秘方(原理篇)
1. B+树の终极奥义
- 三层B+树可存2000W数据(别问,问就是数学算出来的)
- 叶子节点双向链表(范围查询快如闪电)
- 聚簇索引:数据和索引搞基(主键索引就是)
- 二级索引:查完还要回表(能覆盖索引就别骚)
四、慢SQL调优の骚操作(实战篇)
1. EXPLAIN执行计划の玄学解读(升级版!)
-
type列の终极审判:
-
all:全表扫描 → 直接拖出去打手板!
-
index:索引全扫描 → 虽然用索引但和全表扫描差不多(菜鸡互啄)
-
range:索引范围扫描(
BETWEEN
、>
、<
、IN
) → 勉强及格 -
ref:非唯一索引扫描 → 能用但不够优雅
-
eq_ref:唯一索引联表(主键或唯一索引) → 老司机の操作
-
const/system:主键直接命中 → 天选之子!
-
null:不查表不查索引 → 系统白送数据(比如
SELECT 1+1
)
-
-
Extra字段の暗黑信号:
-
Using Where:需要优化=>稍微有点菜
-
Using Temporary:用临时表存结果(
GROUP BY
/ORDER BY
翻车) → 准备挨喷 -
Using Filesort:排序没用索引 → 索引白建警告!
-
Using Join Buffer:联表没走索引 → 菜到抠脚
-
Using Index:覆盖索引直接起飞 → 满分操作!
-
- key列:没用到索引就准备提桶跑路
- rows列:扫描行数超过1W就要拉警报
2. 分页查询の祖传优化
- 反例:limit 100000,10 (直接去世)
- 正解:where id > 上一页最大ID (前提是连续ID)
3.慢SQL语句查看
启用慢查询日志:
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2; -- 设置阈值为2秒
查看慢查询日志位置:
SHOW VARIABLES LIKE 'slow_query_log_file';
使用 Performance Schema
Performance Schema 是MySQL的一个功能强大的性能监控工具,它可以提供更详细的数据库操作监控。
启用 Performance Schema:
SET GLOBAL performance_schema = ON;
你可以通过performance_schema
的表来查询各种性能数据,例如:
SELECT * FROM performance_schema.events_statements_summary_by_digest;
4. 使用 SHOW PROFILE 和 SHOW STATUS
这些命令可以提供查询执行的详细信息,包括CPU使用情况、内存使用情况等。
启用并查看查询分析:
SET profiling = 1;
-- 执行你的查询
SHOW PROFILES;
SHOW PROFILE FOR QUERY [query_id];
五、索引の正确打开方式(血泪案例)
1. 最左前缀原则の经典翻车
- 索引是(a,b,c),where b=1 and c=2 → 索引失效
- 正确姿势:where a=1 and b=2(顺序可以调,但字段不能少)
2. 索引使用の十一诫(违反一条祭天)
-
表必须有主键:用自增列,别用业务字段(防止主键震荡)
-
三大必建索引场景:经常查的字段、联表字段、排序分组字段
-
选择度越高越优先:不重复值/总行数 ≈1(比如手机号)
-
组合索引别超过5列:字段顺序按选择度从高到低排(最左前缀走起)
-
覆盖索引 yyds:别用
SELECT *
,只拿需要的字段(索引直接返回数据美滋滋) -
执行计划必须看:没走索引?优化到它走为止!
-
单表索引别超5个:写操作会哭给你看(维护索引也是要成本的)
-
频繁更新的字段别建索引:索引维护开销原地爆炸
-
别让索引列参与计算:
WHERE age+1>20
→ 索引直接去世 -
联表字段要门当户对:类型必须一致且都建索引
-
隐式转换是魔鬼:
varchar
字段用数字查 → 索引失效(比如WHERE phone=13800138000
,phone是varchar类型)
3.常见的索引失效的情况
隐式类型转换
对索引进行计算或函数
模糊査询(除了 xxxx% 之外,都会导致索引失效)
负方向查询(not、!=、not in)中
少用多表的join、禁止大表join、小表做驱动表、join列的(字符集、类型一致、有索引)尽量避免多层子查询嵌套
select Id, Name from accounts where status = 1 and create_time between '2025-01-01 00:00:00' and '2025-02-10 23:59:59';
4.索引优化
a.时间列
对于默认字段created_at(create_time)、updated_at(update_time)这种默认就应该创建索引,这一般来说是默认的规则。
b.复合索引顺序
有很多人喜欢在创建复合索引的时候,总以为前导列一定是唯一值多的列,例如索引index idx_create_time_status(create_time, status),这个索引往往是无法命中,因为扫描的IO次数太多,总体的cost的比全表扫描还大,CBO最终的选择是走full table scan。
MySQL遵循的是索引最左匹配原则,对于复合索引,从左到右依次扫描索引列,到遇到第一个范围查询(>=, >,<, <=, between …… and ….)就停止扫描,索引正确的索引顺序应该是index idx_status_create_time(status, create_time)。
六、配置参数の调优玄学(参数篇)
1. innodb_buffer_pool_size:建议设置物理内存的70%(但别把OS搞崩),它定义了 InnoDB 缓冲池的大小。缓冲池是一个内存区域,用于缓存数据库中的数据和索引,以加快数据库的读取操作
2. max_connections:别瞎设5000,连接池200够用
3. sync_binlog=1 + innodb_flush_log_at_trx_commit=1(数据安全党必备)
4. 查询缓存?关了吧,这玩意在8.0都被删了(时代的眼泪)
七、数据库设计の三大纪律八项注意
1. 三范式可以破,但要有正当理由(比如故意冗余统计字段)
2. 拒绝所有字段varchar(255)(时间用datetime会死吗?)
3. 大字段单独分表(别让text类型污染主表)
4. 事务代码要短小精悍(长事务=定时炸弹)
5. 单表超500W就要考虑分库分表(具体看业务)
【老哥总结】优化不是玄学,是科学!记住三点:
1. 先诊断再开刀(慢查询日志抓起来)
2. 索引不是银弹(合适才是王道)
3. 架构设计要趁早(等业务量上来就晚了)
看完不点赞,优化全白干!有翻车案例的老铁欢迎评论区Battle!
(新增彩蛋↓↓↓)
【附赠】常见索引翻车公式:
-
WHERE 索引列+1=100
→ 索引失效 -
WHERE userId=12
(字段是varchar) → 隐式转换GG -
ORDER BY 时间列 DESC
(没索引) → Using Filesort警告!