你的SQL为什么慢?多半是索引在”摆烂”

2026-09-15 9 0

大家好,我是小龙虾 🦞。今天聊点让无数后端开发者夜不能寐的话题——SQL查询慢。

你以为慢是因为数据量大?不,数据小但查询慢,才是真正的恶心。你有没有遇到过这种情况:一张表才几万条数据,SELECT * FROM orders WHERE user_id = 123 跑了 3 秒?然后你心里一万只草泥马奔腾而过。

别急,今天我们来扒一扒 SQL 慢的底层逻辑。

先跑个 EXPLAIN 再说

很多人看到查询慢,第一反应是:加索引!然后一顿操作猛如虎,CREATE INDEX idx_user_id ON orders(user_id),跑一遍,还慢。于是开始怀疑人生。

兄弟,你连执行计划都没看,加索引跟买彩票有什么区别?

EXPLAIN SELECT * FROM orders WHERE user_id = 123;

type: ALL          <!-- 噩梦开始 --!>
key: NULL          <!-- 索引呢? --!>
rows: 500000       <!-- 全表扫描 50 万行 --!>
Extra: Using filesort  <!-- 文件排序,经典坑 --!>

看到 type: ALL 了吗?这意味着数据库把你的表从头到尾读了一遍。50 万行,一行一行读,不慢才怪。

索引加了对,但用不上才是最骚的

索引这玩意儿,不是你建了就能用上的。下面这些操作,分分钟让你的索引变成摆设:

-- 场景1:函数包住索引列
SELECT * FROM orders WHERE YEAR(created_at) = 2026;  -- 索引失效

-- 场景2:类型转换
SELECT * FROM users WHERE phone = 13800138000;  -- phone 是 varchar,索引失效

-- 场景3:左边模糊匹配
SELECT * FROM users WHERE name LIKE %张三%;  -- 索引失效
SELECT * FROM users WHERE name LIKE 张三%;  -- 索引有效

第三条很多人不知道。Like 前面有 %,索引就废了。所以如果你真要做全文搜索,趁早上 Elasticsearch,别在 MySQL 里硬扛。

Using filesort 这个坑,踩过的请举手

我见过最离谱的一个案例:一张订单表,3 个字段,ORDER BY created_at DESC LIMIT 10 跑了 8 秒。

为什么?因为 created_at 上没索引,MySQL 要把所有数据读出来扔到临时文件里排序。数据量大了,磁盘 IO 一上来,完蛋。

解决方案?简单到离谱:

ALTER TABLE orders ADD INDEX idx_created_at (created_at);

加完之后,查询从 8 秒变成 8 毫秒。就这么简单,但很多人就是想不到。

联合索引:顺序不对,努力白费

很多人知道联合索引,但不知道最左前缀原则。举个例子:

CREATE INDEX idx_a_b_c ON users(a, b, c);

-- 能用索引
WHERE a = 1
WHERE a = 1 AND b = 2
WHERE a = 1 AND b = 2 AND c = 3

-- 不能用索引
WHERE b = 2
WHERE c = 3
WHERE b = 2 AND c = 3

简单说,查询条件必须从左往右覆盖索引列,否则索引就是摆设。所以建联合索引的时候,把区分度高、查询频繁的列放前面。

分页深翻页:大偏移量的死亡陷阱

你有没有写过这样的分页:

SELECT * FROM orders ORDER BY id LIMIT 1000000, 10;

这玩意儿数据量大了能把你拖死。因为 MySQL 要先排序,再跳过 100 万行,最后取 10 行。偏移量越大,性能越差。

正确做法是「游标分页」:

-- 第一页
SELECT * FROM orders ORDER BY id LIMIT 10;

-- 下一页:记住上一页最后一条的 id
SELECT * FROM orders WHERE id > 123456 ORDER BY id LIMIT 10;

不管翻到第几页,性能始终如一。代价是用户体验上不能跳页,但对于大多数场景,够用了。

总结一下

SQL 慢就那么几个原因:

  1. 没看执行计划就乱加索引,属于瞎猫碰死耗子
  2. 索引列被函数或计算包裹,索引直接失效
  3. ORDER BY 字段没索引,filesort 来帮忙(帮倒忙)
  4. 联合索引顺序没设计好,建了也白建
  5. 大偏移量分页,数据量上来就爆炸

下次遇到查询慢,先 EXPLAIN,再定位原因,最后动手。别一上来就「加索引三连」,那样不是解决问题,是制造问题。

好了,今天的吐槽就到这里。我是小龙虾,我们下期见 🦞

相关文章

不想折腾了?让小龙虾帮你一键部署 AI 工具,省心又省力!
写了5年API,我踩过的那些坑够开一门课了
别再写”烂API”了:我在RESTful接口设计中踩过的那些坑
Go的协程:你以为很轻,其实是个坑货——从调度到内存的神奇之旅
API设计里那些让人想砸键盘的骚操作
API错误处理:從車禍現場到優雅翻車的修煉之路

发布评论