这里总结 MySQL 中 10 种真正能在生产环境中让查询性能“飞升”的高级 SQL 技巧(基于真实场景常见痛点排序,非教科书顺序)。
这些技巧大多能把查询从几秒 → 几十毫秒甚至更低,适用于千万级甚至亿级数据的业务系统。
1. 先过滤、后连接(把 WHERE 条件提前)
最常见、最有效的改写方式之一。
-- 差:先连两个大表,再过滤
SELECT ...
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.create_time > '2025-01-01';
-- 好:先把大表过滤到很小,再连接
SELECT ...
FROM (
SELECT * FROM orders
WHERE create_time > '2025-01-01'
) o
JOIN users u ON o.user_id = u.id;
效果:当 orders 表很大但符合时间条件的只有 1% 时,性能可能提升 10–100 倍。
2. 覆盖索引 + 索引下推(Index Condition Pushdown)
让查询只读索引、不回表。
-- 普通索引
CREATE INDEX idx_user_status ON users(status, create_time);
-- 推荐:覆盖 + 常用排序字段放前面
CREATE INDEX idx_status_create ON users(status, create_time, id);
SELECT id, create_time
FROM users
WHERE status = 1
ORDER BY create_time DESC
LIMIT 20;
额外加分:MySQL 5.6+ 自动支持索引下推,WHERE 后面的条件尽量放在索引中。
3. 强制 / 提示使用索引(当优化器判断失误时)
SELECT ...
FROM orders FORCE INDEX(idx_create_time_status)
WHERE create_time > '2025-01-01'
AND status = 'paid';
或使用 USE INDEX、IGNORE INDEX。
适用场景:统计信息不准、数据分布极端、临时大表等。
4. 延迟关联 / 派生表 + LIMIT 优化大分页
-- 差:千万级表深分页
SELECT * FROM logs ORDER BY id DESC LIMIT 1000000, 10;
-- 好:先通过主键/索引找到 id,再回表
SELECT l.*
FROM logs l
INNER JOIN (
SELECT id FROM logs
ORDER BY id DESC
LIMIT 1000000, 10
) t ON l.id = t.id;
效果:从 10 秒 → 几十毫秒。
5. 用 JOIN 代替 IN / EXISTS(很多时候更快)
-- 旧写法(子查询)
SELECT * FROM orders
WHERE user_id IN (SELECT id FROM users WHERE level > 5);
-- 改写为 JOIN(通常更快)
SELECT o.*
FROM orders o
INNER JOIN users u ON o.user_id = u.id
WHERE u.level > 5;
注意:MySQL 8.0+ 子查询优化已经很强,但 JOIN 仍然在很多场景下更可控。
6. GROUP BY + ORDER BY 优化(利用索引避免 filesort)
-- 差:需要额外排序
SELECT user_id, COUNT(*) cnt
FROM orders
GROUP BY user_id
ORDER BY cnt DESC
LIMIT 10;
-- 好:提前建好复合索引
CREATE INDEX idx_user_amount ON orders(user_id, total_amount);
SELECT user_id, SUM(total_amount)
FROM orders
GROUP BY user_id
ORDER BY SUM(total_amount) DESC
LIMIT 10;
小技巧:ORDER BY 的字段尽量和 GROUP BY 一致,或放在索引最后。
7. 批量操作代替逐行(INSERT/UPDATE/DELETE)
-- 慢:循环单条插入
INSERT INTO log VALUES (...);
INSERT INTO log VALUES (...);
-- 快:批量 + VALUES 多行
INSERT INTO log (col1,col2,col3)
VALUES
(...),
(...),
(...);
更极致:使用 LOAD DATA INFILE 或 MySQL 的批量 API,速度可提升几十倍。
8. 避免隐式类型转换和函数操作索引字段
-- 索引失效
WHERE phone = 13812345678 -- 字符串字段用了数字
WHERE DATE(create_time) = '2025-02-01'
WHERE LEFT(name, 3) = '张三'
-- 正确
WHERE phone = '13812345678'
WHERE create_time >= '2025-02-01' AND create_time < '2025-02-02'
WHERE name LIKE '张三%'
9. 巧用 UNION ALL 代替 UNION(避免去重)
-- 慢:要去重
SELECT ... FROM table1 UNION SELECT ... FROM table2;
-- 快:不去重(业务允许时)
SELECT ... FROM table1 UNION ALL SELECT ... FROM table2;
10. 用临时表 / 物化视图 / 分区表 处理超复杂聚合
当单条 SQL 已经非常复杂(多层嵌套、大量聚合)时,考虑拆成多步:
- 先生成中间结果存临时表(Memory 引擎更快)
- 再从临时表查询
- 或者直接使用分区表(PARTITION BY RANGE/KEY)
示例(日活/月活统计常用):
CREATE TEMPORARY TABLE tmp_active_users ENGINE=MEMORY
SELECT DISTINCT user_id FROM login_log
WHERE login_time >= '2025-02-01';
SELECT COUNT(*) FROM tmp_active_users;
快速总结口诀(背下来就能少踩坑)
- 先过滤再连接
- 覆盖索引 + 索引下推
- 避免 SELECT *、函数、类型转换
- 大分页用延迟关联
- 子查询 → JOIN
- filesort 用索引避免
- 批量 > 循环单条
- UNION ALL > UNION
- 复杂逻辑 → 中间表/分区
- 永远先 EXPLAIN
你当前最常遇到哪一类慢查询?可以贴出来,我帮你针对性优化。MySQL的10种高级SQL,性能飞升