🚀 SQL 慢查询拯救计划:7 个实战案例,让你的 SQL 飞起来!

57 阅读4分钟

“系统怎么又卡了?”
“数据库 CPU 飙到 90% 了!”
“快看看是不是又有慢 SQL!”

在后端开发中,SQL 优化是每个开发者必须掌握的硬核技能。很多时候,我们写的 SQL 在开发环境跑得飞快,一上线遇到大数据量就“原形毕露”。

今天,我们不讲枯燥的索引原理,直接上 7 个真实的慢 SQL 案例,手把手教你如何分析和优化,让你的 SQL 性能提升 10 倍甚至 100 倍!

案例一:最左前缀法则失效 🚫

场景:用户表 user 有个联合索引 idx_name_age (name, age)。

❌ 慢 SQL

SELECT * FROM user WHERE age = 20;

💥 原因分析
联合索引遵循**“最左前缀法则”**。查询条件必须从索引的最左边列开始,否则索引失效。
这里直接查 age,跳过了 name,导致索引失效,全表扫描。

✅ 优化方案

  1. 修改查询:如果业务允许,带上 name 条件。

    SELECT * FROM user WHERE name = '张三' AND age = 20;

  2. 新建索引:如果经常单独查 age,给 age 单独建个索引。

案例二:索引列上做计算 🧮

场景:查询 2024 年注册的用户。

❌ 慢 SQL

SELECT * FROM user WHERE YEAR(create_time) = 2024;

💥 原因分析
在索引列上使用函数(YEAR())或进行计算(+ - * /),会导致数据库无法使用索引树进行查找,只能全表扫描。

✅ 优化方案
把计算放到等号右边,或者改写成范围查询。

SELECT * FROM user WHERE create_time BETWEEN '2024-01-01 00:00:00' AND '2024-12-31 23:59:59';

案例三:隐式类型转换 🎭

场景:用户手机号 phone 字段是 varchar 类型,且建了索引。

❌ 慢 SQL

SELECT * FROM user WHERE phone = 13800138000;

💥 原因分析
查询条件里 138... 是数字类型,而数据库字段是字符串。MySQL 会自动把字符串转成数字进行比较,这相当于在索引列上做了函数操作,导致索引失效。

✅ 优化方案
参数加上单引号,保持类型一致。

SELECT * FROM user WHERE phone = '13800138000';

案例四:深分页问题 📜

场景:查询第 100 万页的数据。

❌ 慢 SQL

SELECT * FROM user LIMIT 1000000, 10;

💥 原因分析
MySQL 需要先查出前 1000010 条记录,然后丢弃前 1000000 条,只取最后 10 条。这会产生大量的回表操作,性能极差。

✅ 优化方案
延迟关联 (Late Row Lookups) :先通过覆盖索引查出 ID,再根据 ID 查详情。

SELECT t1.* FROM user t1
INNER JOIN (SELECT id FROM user LIMIT 1000000, 10) t2 ON t1.id = t2.id;

案例五:OR 查询导致索引失效 ⚖️

场景:查询 id = 1 或者 age = 20 的用户。id 有索引,age 没索引。

❌ 慢 SQL

SELECT * FROM user WHERE id = 1 OR age = 20;

💥 原因分析
OR 查询中,只要有一个条件列没有索引,那么涉及的索引都不会被用到,直接全表扫描。

✅ 优化方案
使用 UNION 代替 OR。

(SELECT * FROM user WHERE id = 1)
UNION
(SELECT * FROM user WHERE age = 20);

案例六:SELECT * 的滥用 📦

场景:只需要用户的手机号,却查了所有字段。

❌ 慢 SQL

SELECT * FROM user WHERE name = '张三';

💥 原因分析
SELECT * 会查询出所有字段,包括大文本字段,增加了网络传输和内存开销。更重要的是,它无法利用覆盖索引 (Covering Index) ,必须回表查询。

✅ 优化方案
只查需要的字段。

SELECT phone FROM user WHERE name = '张三';

如果 idx_name_phone 存在,这句 SQL 可以直接从索引树拿到数据,无需回表,速度飞快!

案例七:like 模糊查询 % 在前 🔍

场景:根据名字模糊查询。

❌ 慢 SQL

SELECT * FROM user WHERE name LIKE '%三';

💥 原因分析
B+ 树索引是按照从左到右的顺序排列的。如果 % 在最前面,数据库不知道从哪里开始找,只能全表扫描。

✅ 优化方案

  1. % 在后:LIKE '张%' 是走索引的。
  2. 覆盖索引:如果只查 ID,SELECT id FROM user WHERE name LIKE '%三' 是可以走索引扫描的。
  3. 搜索引擎:如果必须全模糊匹配,建议走 Elasticsearch。

💡 架构师总结

SQL 优化不是玄学,而是有迹可循的科学。

  1. Explain 是神器:写完 SQL,养成习惯用 EXPLAIN 看看执行计划,有没有走索引 (type 是不是 ALL)。
  2. 索引不是越多越好:索引会降低写入速度,占用磁盘空间。要根据查询场景精准建索引。
  3. 代码层面的优化:有时候 SQL 很难优化了,可以考虑加缓存、分库分表或者业务降级。

希望这篇文章能帮你消灭慢 SQL,让你的系统如丝般顺滑!