MySQL 索引优化实战:提升查询性能 10 倍 原创
温馨提示:
本文最后更新于 2026-04-02,已超过 2 天没有更新。
若文章内的图片失效(无法正常加载),请留言反馈或直接 联系我。
数据库性能是系统性能的关键瓶颈。本文深入讲解 MySQL 索引优化技巧,帮助开发者提升查询效率。
一、索引基础原理
1.1 B+ 树结构
MySQL InnoDB 使用 B+ 树存储索引,特点:
- 非叶子节点只存储键值
- 叶子节点存储完整数据
- 叶子节点之间用链表连接
1.2 聚簇索引 vs 二级索引
聚簇索引的叶子节点存储完整行数据,二级索引叶子节点存储主键值。
二、索引创建策略
2.1 选择合适的列
-- ✅ 适合创建索引
WHERE user_id = 123
WHERE created_at > '2026-01-01'
JOIN orders ON users.id = orders.user_id
-- ❌ 不适合创建索引
WHERE status IN (0, 1) -- 区分度低
WHERE gender = 'M' -- 区分度低
2.2 复合索引设计
-- 最左前缀原则
CREATE INDEX idx_user_time ON orders(user_id, created_at);
-- ✅ 可以使用索引
WHERE user_id = 1
WHERE user_id = 1 AND created_at > '2026-01-01'
-- ❌ 不能使用索引
WHERE created_at > '2026-01-01'
三、查询优化
3.1 EXPLAIN 分析
EXPLAIN SELECT * FROM orders WHERE user_id = 123;
-- 关注字段:
-- type: system > const > eq_ref > ref > range > index > ALL
-- key: 实际使用的索引
-- rows: 扫描行数
-- Extra: Using index(好) / Using temporary(需优化)
3.2 避免索引失效
-- ❌ 索引失效
WHERE YEAR(created_at) = 2026
WHERE name LIKE '%张%'
WHERE age != 25
WHERE phone = 13800000000 OR email = 'test@test.com'
-- ✅ 索引有效
WHERE created_at >= '2026-01-01' AND created_at < '2027-01-01'
WHERE name LIKE '张%'
WHERE age = 25
UNION ALL 代替 OR
四、覆盖索引优化
查询的列都在索引中,无需回表。
-- 创建覆盖索引
CREATE INDEX idx_user_status ON orders(user_id, status);
-- 使用覆盖索引
SELECT user_id, status FROM orders WHERE user_id = 123;
五、分页优化
-- ❌ 慢查询(深度分页)
SELECT * FROM orders ORDER BY id LIMIT 1000000, 10;
-- ✅ 优化方案 1:延迟关联
SELECT o.* FROM orders o
INNER JOIN (SELECT id FROM orders LIMIT 1000000, 10) tmp
ON o.id = tmp.id;
-- ✅ 优化方案 2:记录上次 ID
SELECT * FROM orders WHERE id > 1000000 LIMIT 10;
六、表结构优化
6.1 选择合适的数据类型
-- ✅ 更小更好
TINYINT < SMALLINT < INT < BIGINT
VARCHAR(20) < VARCHAR(255)
DATETIME < TIMESTAMP (根据需求选择)
6.2 垂直分区
将大字段拆分到独立表。
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100)
);
CREATE TABLE users_profile (
user_id INT PRIMARY KEY,
bio TEXT,
avatar VARCHAR(255)
);
七、实战案例
7.1 订单查询优化
-- 优化前:2.5 秒
SELECT * FROM orders
WHERE user_id = 123
ORDER BY created_at DESC
LIMIT 20;
-- 优化后:0.05 秒
CREATE INDEX idx_user_created ON orders(user_id, created_at);
7.2 统计查询优化
-- 优化前:全表扫描
SELECT COUNT(*) FROM orders WHERE status = 1;
-- 优化后:使用覆盖索引
CREATE INDEX idx_status ON orders(status);
八、监控与维护
8.1 慢查询日志
[mysqld]
slow_query_log = 1
long_query_time = 1
log_queries_not_using_indexes = 1
8.2 索引维护
-- 分析表
ANALYZE TABLE orders;
-- 检查索引使用情况
SELECT * FROM sys.schema_unused_indexes;
九、总结
- 理解 B+ 树原理是优化的基础
- 使用 EXPLAIN 分析查询计划
- 避免常见索引失效场景
- 定期监控慢查询
- 根据实际业务调整索引策略
数据库优化需要持续监控和调整,建议建立性能基线定期对比。
十、高级优化技巧
10.1 索引下推 (ICP, MySQL 5.6+)
在索引遍历过程中进行条件过滤,减少回表次数。
-- 启用 ICP
SET optimizer_switch='index_condition_pushdown=on';
-- 适用场景
SELECT * FROM users WHERE name LIKE '张%' AND age > 20;
-- ICP 可以在索引层过滤 age > 20
10.2 不可见索引
测试删除索引的影响,无需真正删除。
ALTER TABLE orders ALTER INDEX idx_user INVISIBLE;
-- 观察性能变化
ALTER TABLE orders ALTER INDEX idx_user VISIBLE;
十一、分区表优化
11.1 RANGE 分区
CREATE TABLE orders (
id INT, order_date DATE
) PARTITION BY RANGE (YEAR(order_date)) (
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p2025 VALUES LESS THAN (2026)
);
十二、总结
- 理解 B+ 树原理
- 使用 EXPLAIN 分析查询
- 避免索引失效
- 定期监控慢查询
- 建立性能基线
数据库优化是持续过程。