MySQL优化是老话题了,但很多工程师搞了很久还是在重复踩同样的坑。这篇整理7个实战中容易忽略的细节,助你一次性把性能提上去。
1. 索引不是越多越好
很多人觉得”查慢就加索引”,结果表里有十几条索引,写性能严重下降。索引是一把双刃剑:读加速,写变慢。每增加一个索引,INSERT/UPDATE都要维护对应B+树。原则:单表索引不超过5个,只给WHERE/ON条件字段建索引。
2. LIKE前面不能加%
-- 失效:LIKE以通配符开头,索引无法命中
SELECT * FROM orders WHERE order_no LIKE '%2026%';
-- 生效:LIKE以具体值开头
SELECT * FROM orders WHERE order_no LIKE '2026%';
-- 如果必须前缀匹配,用Redis或ES替代MySQL
3. COUNT(*) 和 COUNT(1) 性能一样?
在InnoDB中,COUNT(*)需要扫描全表或索引来获取行数,COUNT(1)本质上一样。真正快的方案:建一个单独的计数字段,用触发器或应用层维护。适用于频繁需要COUNT的场景(如帖子评论数)。
4. 慢查询日志不是摆设
-- 开启慢查询日志(生产环境建议持续开启)
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;
-- 用EXPLAIN分析(重点看type/key/rows)
EXPLAIN SELECT * FROM orders WHERE status = 'paid';
5. 联合索引遵守最左前缀原则
-- 建了联合索引 (status, created_at, user_id)
-- 能命中索引:
WHERE status = 'paid' AND created_at > '2026-01-01' -- 命中
WHERE status = 'paid' -- 命中
-- 不能命中索引:
WHERE created_at > '2026-01-01' -- 跳过status,无法命中
6. JOIN记得指定驱动顺序
MySQL优化器不总是选对JOIN顺序。用STRAIGHT_JOIN强制指定JOIN顺序,小表在前、大表在后:
SELECT * FROM large_orders o
STRAIGHT_JOIN users u ON o.user_id = u.id
STRAIGHT_JOIN products p ON o.product_id = p.id;
-- large_orders(数据最多)放在最前面,驱动它扫描一次即可
7. 批量插入用LOAD DATA INFILE
-- 普通INSERT:每条单独commit,网络往返开销大
INSERT INTO orders VALUES (1,'A'),(2,'B'); -- 1000条=1000次网络
-- LOAD DATA:文件级导入,速度快10-50倍
LOAD DATA LOCAL INFILE '/tmp/orders.csv'
INTO TABLE orders
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\\n';
-- 数据量大时,先禁用索引再重建
ALTER TABLE orders DISABLE KEYS;
LOAD DATA ...
ALTER TABLE orders ENABLE KEYS;
总结
| 知识点 | 核心要点 |
|---|---|
| 索引不是越多越好 | 单表不超过5个索引,读快写慢 |
| LIKE前加%失效 | 前缀匹配才能命中索引 |
| COUNT性能 | InnoDB全表扫描,考虑计数字段 |
| 慢查询日志 | 生产环境持续开启,EXPLAIN分析 |
| 最左前缀原则 | 联合索引从左到右使用,不能跳过中间 |
| JOIN顺序 | 小表驱动大表,大表在前用STRAIGHT_JOIN |
| 批量插入 | LOAD DATA INFILE比INSERT快10-50倍 |
MySQL优化没有捷径,但方向对了就不怕路远。慢查询日志+EXPLAIN是标配,索引合理化是根本,架构层面的读写分离和分库分表是大招。
⚠️ 声明:本文相关内容仅供参考。