LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

90% 的慢 SQL,都不是因为数据量大,而是“写得烂”

admin
2026年4月13日 22:36 本文热度 13

很多人一看到 SQL 跑得慢,第一反应就是:数据量太大了。

这话有时候没错,但更多时候,它只是个看起来很合理的借口。

真实情况往往更扎心: 表不算大,机器也还行,索引甚至都建了,SQL 还是慢。
那问题多半不在“数据量”,而在 SQL 写法把数据库优化器整不会了

说得更直接一点: 慢 SQL,大多数不是“扛不住”,而是“写得烂”。

今天这篇,就聊几个最常见、最有代表性的坑。你会发现,很多性能问题,根本不是升级机器能解决的。


一、不是数据量大,而是你先让索引失效了

数据库性能优化里,索引像高速公路。
你明明修了路,结果 SQL 一写,自己先把路封了,然后还怪车多。

最典型的几种写法:

1. 对索引列做函数计算

比如:

SELECT *
FROM orders
WHERE DATE(create_time) = '2026-03-01';

如果 create_time 上有索引,很多人以为这条语句会走索引。
但现实通常是:不会。

因为你对列做了 DATE() 运算,数据库没法直接利用原始索引值,只能老老实实扫大量数据再计算。

更好的写法:

SELECT *
FROM orders
WHERE create_time >= '2026-03-01 00:00:00';
  AND create_time < '2026-03-02 00:00:00';

这类范围查询,才更容易真正利用索引。

2. 隐式类型转换

比如手机号是字符串类型,你却拿数字去查:

SELECT *
FROM user_profile
WHERE phone = '13800138000';

看起来只是少打了两个引号,实际上数据库可能要做类型转换。
一旦转换方向不友好,索引利用率就会直接掉下去。

别小看这种低级错误。
线上很多“偶发性慢 SQL”,本质就是这种代码细节导致的。

3. 前导模糊匹配

SELECT *
FROM product
WHERE product_name LIKE '%咖啡';

LIKE '%xxx' 这种前面带 % 的写法,B+ 树索引基本帮不上忙。
因为它无法从有序前缀开始定位,只能靠扫描。

如果你的业务里这种查询非常常见,那就别硬拿普通索引扛:

  • • 要么改业务检索方式
  • • 要么上倒排索引 / 全文检索
  • • 要么单独设计搜索服务

别拿数据库当搜索引擎,还怪它不够快。


二、不是数据多,而是你查了太多没用的数据

很多 SQL 慢,问题甚至不在条件,而在 你拿太多了

1. SELECT * 是性能懒癌

SELECT *
FROM orders
WHERE user_id = 1001;

这句写起来最省事,后果通常最不省事。

为什么?

  • • 读取了根本用不到的列
  • • 增加了磁盘 IO
  • • 增加了网络传输
  • • 可能让覆盖索引失效

如果你真正只需要:

SELECT order_id, amount, status
FROM orders
WHERE user_id = 1001;

那就老老实实只查这三列。

很多场景下,字段一收窄,性能就肉眼可见地好起来。

2. 没有限制返回行数

有些接口明明前端只展示 20 条,你后端 SQL 却先捞 5 万条回来,再在代码里慢慢处理。

这不是数据库慢,这是你对数据库不太客气。

该加 LIMIT 的地方就加,
该做分页的地方就分页,
该做游标翻页的地方别硬上深分页。


三、不是数据量问题,而是 JOIN / 子查询写得太任性

SQL 慢,不少时候慢在“关系太复杂”,不是“数据太大”。

1. 小表驱动大表,不是玄学,是常识

如果多表关联时,过滤条件没有尽早生效,数据库可能会先生成很大的中间结果集,再一步步筛。

这就像你先把全公司的人都拉进会议室,再问一句“做后端的留下”。

不慢才怪。

优化思路通常包括:

  • • 先过滤再关联
  • • 给关联列加合适索引
  • • 避免无谓的宽表 JOIN
  • • 看执行计划,确认驱动表是否合理

2. 子查询不是原罪,但乱写会出事

比如相关子查询:

SELECT u.id,
       (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) AS order_cnt
FROM users u;

如果外层 users 记录很多,内层子查询可能被反复执行。

在一些场景下,改成聚合后再 JOIN,性能会稳定很多:

SELECT u.id, t.order_cnt
FROM users u
LEFT JOIN (
    SELECT user_id, COUNT(*) AS order_cnt
    FROM orders
    GROUP BY user_id
) t ON u.id = t.user_id;

当然,具体还要看数据库版本、优化器能力和实际执行计划。
但有一点不会变: 别只看 SQL 能不能跑,要看它到底怎么跑。


四、不是表太大,而是排序、分组没借上索引的力

1. ORDER BY 一旦排不动,就开始消耗内存和磁盘

SELECT id, user_id, create_time
FROM orders
WHERE status = 'paid';
ORDER BY create_time DESC;

如果 statuscreate_time 上没有形成合适的联合索引,数据库就可能先筛选,再做额外排序。

数据一多,排序成本非常高,甚至会产生临时文件。

很多人看到慢,就说“因为订单表太大”。
其实更准确的说法是: 你想排序,但没给数据库一条能顺着走的路。

2. GROUP BY 也一样

分组统计本身就有成本。
如果还能顺着索引分组,成本会低很多;
如果不能,就容易出现临时表、额外排序、CPU 飙高。

所以别只盯着 where 条件建索引,
ORDER BYGROUP BY 的字段顺序,也常常决定了这条 SQL 的生死。


五、不是数据量大,而是分页方式错了

很多后台系统一上来就是这种分页:

SELECT *
FROM orders
ORDER BY id
LIMIT 100000, 20;

这类深分页,页数越往后越慢。
原因不是数据库突然变笨了,而是它需要先跳过前面大量数据,再拿后面的 20 条。

这就像让人从一本 10 万页的书里,先翻过前 99980 页,再给你看最后 20 页。

更稳的方式通常是 基于游标或主键翻页

SELECT *
FROM orders
WHERE id > 100000
ORDER BY id
LIMIT 20;

如果业务允许,这种方式通常比 LIMIT offset, size 可靠得多。


六、不是数据库不行,而是你根本没看执行计划

很多性能问题,讨论半天都停留在猜测层面:

  • • 是不是数据太大?
  • • 是不是数据库版本不行?
  • • 是不是机器配置不够?
  • • 是不是该分库分表了?

结果一看 EXPLAIN,发现压根没走索引。

这就像病人咳嗽两声,你直接提议换器官。

先看这几个关键信号:

  • • type:是不是全表扫描
  • • key:实际用了哪个索引
  • • rows:预估扫描了多少行
  • • Extra:有没有 Using filesortUsing temporary

很多所谓的大问题,执行计划一拉出来,十分钟就能定位。

别上来就谈架构升级。
先看看是不是一条 SQL 写得不太像样。


七、什么时候“数据量大”才真的是核心问题?

说了这么多,不是要否认数据量的影响。

数据量当然会带来性能压力,尤其在这些场景里:

  • • 热数据非常集中
  • • 单表达到千万、上亿级别
  • • 统计分析型查询很多
  • • 索引体积巨大,缓存命中下降
  • • 写入频繁,索引维护成本高

但重点是: 很多团队还没到那个量级,就已经先把 SQL 写出了亿级数据的灾难感。

也就是说,
本来是“自行车通勤”,
非要把自己骑出“横穿无人区”的痛苦体验。


八、排查慢 SQL,建议按这 5 步走

如果你想系统一点排查,建议按这个顺序:

1. 先看执行计划

不要猜,先确认有没有走索引、扫描了多少行、有没有临时表和额外排序。

2. 看查询条件是否让索引失效

重点查:

  • • 函数操作
  • • 隐式转换
  • • 前导模糊匹配
  • • 不合理的联合索引顺序

3. 看是不是查了太多字段、太多行

能不能去掉 SELECT *
能不能缩小结果集?
能不能提前过滤?

4. 看 JOIN、排序、分组是否设计合理

很多 SQL 慢,不在 where,而在 join / order by / group by。

5. 最后再考虑数据量和架构问题

如果 SQL 写法已经比较健康,索引也合理,执行计划也没明显问题,这时候再考虑分库分表、冷热分离、缓存、搜索引擎替代等方案。

顺序别反了。
一上来就上大手术,通常只是把一个小毛病包装成大项目。


结语

慢 SQL 这件事,最误导人的一句话就是: “因为数据量大。”

它听起来专业,甩锅也方便,甚至还能顺便为后续买机器、上中间件、做复杂架构铺垫。

但很多时候,真相没那么宏大。

真相往往是:

  • • 索引失效了
  • • 查多了
  • • 排序方式不对
  • • 分页写法不对
  • • 执行计划压根没看

所以,下次再遇到慢 SQL,先别急着怪数据量。

先问一句更实际的话: 这条 SQL,到底是不是“像个懂事的 SQL”?

这个问题,通常比“表有多大”更接近真相。


阅读原文:原文链接


该文章在 2026/4/14 16:15:11 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-2  粤公网安备44030602007207号