MySQL的10种高级SQL,性能飞升

这里总结 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 INDEXIGNORE 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,性能飞升

文章已创建 4631

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部