MySQL 查询优化实战:从索引、执行计划到SQL调优全攻略
MySQL 查询优化实战指南:从原理到落地实践
在日常的后端开发中,MySQL 查询优化是一项极其重要的技能。一个低效的 SQL 查询可能拖垮整个系统性能,而经过优化的查询则能让系统飞起来。本文将从优化原理、实际案例、执行计划分析、索引策略和调优技巧几个角度,帮你彻底理解 MySQL 查询优化。
一、为什么要做 MySQL 查询优化?
数据库性能瓶颈往往来自:
- 索引缺失或误用 —— 没有合适的索引导致全表扫描。
- SQL 语句不当 —— 例如
SELECT *、子查询过多、函数包裹字段等。 - 数据量暴增 —— 业务增长后原有 SQL 性能急剧下降。
- 表设计不合理 —— 范式不当、字段类型不匹配导致存储浪费。
优化的目的就是让查询走“最短路径”,以最小的成本拿到正确结果。
二、基础优化:从索引入手
索引是 MySQL 查询优化的核心。正确使用索引能将查询速度提升数百倍。
✅ 建立高效索引
常见优化思路:
- WHERE 条件字段建索引:
CREATE INDEX idx_user_name ON user(name); - 联合索引要注意最左前缀原则:
CREATE INDEX idx_user_status_time ON user(status, create_time); -- 等价于可使用 (status)、(status, create_time),但不能单独用 create_time - 避免在索引字段上使用函数:
-- 错误:会导致索引失效 SELECT * FROM user WHERE DATE(create_time) = '2025-11-12'; -- 正确写法 SELECT * FROM user WHERE create_time >= '2025-11-12 00:00:00' AND create_time < '2025-11-13 00:00:00';
三、使用 EXPLAIN 分析执行计划
EXPLAIN 是分析 SQL 性能的利器,它可以帮助我们了解 MySQL 如何执行查询。
EXPLAIN SELECT * FROM orders WHERE user_id = 1001 AND status = 'paid';
输出关键字段说明:
| 字段 | 含义 |
|---|---|
| type | 访问类型,值越靠近 const 性能越好,如:ALL(全表扫描)、index、range、ref、eq_ref、const |
| key | 使用的索引 |
| rows | 预估扫描的行数 |
| Extra | 是否使用临时表或文件排序 |
例如:
id | select_type | table | type | possible_keys | key | rows | Extra
1 | SIMPLE | orders| ref | idx_user_status | idx_user_status | 50 | Using where
说明该查询使用了联合索引 idx_user_status,扫描行数较少,性能良好。
四、SQL 优化实战案例
示例 1:分页查询优化
低效写法:
SELECT * FROM order_log ORDER BY id LIMIT 100000, 20;
问题:OFFSET 较大时,MySQL 需要扫描前面 10 万行再丢弃。
优化方案:
SELECT * FROM order_log WHERE id > 100000 ORDER BY id LIMIT 20;
通过记录上次的 id,直接从下一个起始点查起,效率可提升数百倍。
示例 2:子查询优化
-- 低效写法
SELECT * FROM user WHERE id IN (SELECT user_id FROM orders WHERE status='paid');
-- 高效写法(使用 JOIN)
SELECT u.* FROM user u
JOIN orders o ON u.id = o.user_id
WHERE o.status='paid';
MySQL 在 5.6 以前对子查询优化较差,建议尽量改为 JOIN。
五、表结构与字段设计优化
- 避免使用 TEXT/BLOB 类型,能用 VARCHAR 就用 VARCHAR。
- 合理设置字段长度:过长字段会导致页分裂和存储浪费。
- 尽量使用整型代替字符串:
-- 不推荐 SELECT * FROM user WHERE phone = '13888888888'; -- 推荐 SELECT * FROM user WHERE phone_hash = 1888888888; - 冷热数据分表:活跃数据与历史数据拆分,提高缓存命中率。
六、高级优化技巧
1. 使用 SQL_CALC_FOUND_ROWS 慎重
SELECT SQL_CALC_FOUND_ROWS * FROM orders LIMIT 20;
SELECT FOUND_ROWS();
虽然方便分页统计,但性能极差,不建议在大表使用。
2. 利用 covering index(覆盖索引)
当查询的字段全部在索引中时,无需回表操作:
CREATE INDEX idx_order_user_status ON orders(user_id, status);
SELECT user_id, status FROM orders WHERE user_id=1;
3. 使用缓存与分库分表
- Redis 缓存热点查询结果
- 分库分表 降低单库压力
- 读写分离 提高吞吐能力
七、总结
MySQL 查询优化是一个系统性工程,既要懂 SQL,又要理解执行计划和底层存储原理。一般优化顺序为:
- 分析慢 SQL(通过慢查询日志 + EXPLAIN)
- 优化 SQL 语句结构
- 调整索引设计
- 进行缓存与架构级优化
持续监控与分析,才能让数据库长久保持高性能。
正文到此结束
相关文章
热门推荐
评论插件初始化中...