数据库性能问题是后端开发中最常见的瓶颈。然而,很多开发者的"优化"就是在字段上加个索引——然后发现还是慢。本文将系统梳理 MySQL 性能调优的三个核心维度:索引优化、SQL 调优和分库分表,并介绍 Druid 监控工具的使用。
索引优化的本质:数据结构的选择
B+Tree 为什么是 MySQL 的首选?
B+Tree 的所有数据都存在叶子节点,非叶子节点只存索引——这让单次磁盘 I/O 能检索更多索引键。在 16KB 的 InnoDB 页中,假设主键是 BIGINT(8字节)+ 指针(6字节),一个非叶子节点大约能存 16KB / 14B ≈ 1170 个索引键。三层 B+Tree(根→中间→叶子)约能索引 1170 × 1170 × 16 ≈ 两千万行。这意味着绝大多数 OLTP 查询只需 1~3 次磁盘 I/O。
最左前缀原则:面试必问
CREATE INDEX idx_a_b_c ON users(a, b, c);
-- 走索引(匹配最左前缀)
SELECT * FROM users WHERE a = 1;
SELECT * FROM users WHERE a = 1 AND b = 2;
-- 不走索引(跳过了 a)
SELECT * FROM users WHERE b = 2;
SELECT * FROM users WHERE c = 3;
-- 部分走索引(a 走索引,c 不走)
SELECT * FROM users WHERE a = 1 AND c = 3;索引失效的常见场景
-- 1. 函数操作(索引列参与计算)
SELECT * FROM orders WHERE DATE(create_time) = '2025-01-01'; -- 失效!
-- 改为:WHERE create_time >= '2025-01-01' AND create_time < '2025-01-02';
-- 2. 隐式类型转换
SELECT * FROM users WHERE phone = 13800138000; -- phone 是 VARCHAR,失效!
-- 3. LIKE 前置模糊
SELECT * FROM articles WHERE title LIKE '%MySQL%'; -- 完全失效
-- 4. OR 条件不全有索引
SELECT * FROM users WHERE name = 'ABC' OR age = 25; -- age 没有索引覆盖索引:最优雅的性能优化
CREATE INDEX idx_name_age ON users(name, age);
SELECT name, age FROM users WHERE name = 'ABC'; -- 不需要回表!SQL 执行计划分析(EXPLAIN 必看项)
EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 'paid';
-- 关键指标
-- type: const > eq_ref > ref > range > index > ALL(绝对不能出现 ALL)
-- key: 实际使用的索引
-- rows: 扫描行数(越小越好)
-- Extra: Using filesort / Using temporary(出现就说明需要优化)慢查询分析:找到瓶颈
-- 开启慢查询日志
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;
-- 用 mysqldumpslow 分析
mysqldumpslow -s t -t 10 /var/log/mysql/slow.logDruid SQL 监控
// Spring Boot 集成 Druid
spring:
datasource:
druid:
stat-view-servlet:
enabled: true
url-pattern: /druid/*
login-username: admin
login-password: admin
filter:
stat:
enabled: true
slow-sql-millis: 1000
log-slow-sql: true通过 /druid/index.html 可视化查看:SQL 执行次数、耗时分布、连接池状态、慢查询列表。
分库分表策略
垂直分库:按业务拆分
用户库(user_db)、订单库(order_db)、商品库(product_db),各库独立部署、独立扩容。
水平分表:ShardingSphere-JDBC 配置
# sharding.yml
rules:
- !SHARDING
tables:
t_order:
actualDataNodes: ds0.t_order_$->{0..15}
databaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: db_inline
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: order_inline
shardingAlgorithms:
db_inline:
type: INLINE
props:
algorithm-expression: ds$->{user_id % 2}
order_inline:
type: INLINE
props:
algorithm-expression: t_order_$->{order_id % 16}总结
MySQL 优化有一个优先级:SQL 优化 > 索引优化 > 架构优化。大多数性能问题的根源在于糟糕的 SQL 和缺失的索引,而不是"数据库配置参数不够好"。Druid 监控是你发现这些问题的眼睛,而分库分表是最后的底牌——在此之前,请先确保 SQL 和索引已经做到最好。
评论 (0)