一条 SQL 查了 8 秒,我加了个索引就变成 0.02 秒

42 阅读3分钟

前几天,线上有个接口突然慢了。

用户点一下,转圈转八秒。

八秒是什么概念?够用户点十次"刷新",然后关掉你的页面。

我去查日志,定位到一条 SQL。

慢在哪

这条 SQL 很简单:

SELECT * FROM orders WHERE user_id = 12345;

看着没毛病对吧?

问题在于,这张 orders 表有三百万行数据,而 user_id 这一列,没有索引。

没有索引意味着什么?意味着数据库要从第一行开始,一行一行地找,一直找到最后一行。

三百万行,全部扫一遍。

这就是所谓的全表扫描。

八秒,就是它扫完三百万行花的时间。

加了个索引

我加了一行:

CREATE INDEX idx_user_id ON orders(user_id);

再跑一次那条 SQL。

0.02 秒。

从八秒到 0.02 秒,快了 400 倍。

就加了一行代码,什么问题都没了。

索引为什么这么快

索引这个东西,可以理解成书的目录。

一本书几百页,你要找某个关键词。没有目录,你就得一页一页翻。有了目录,你直接翻到对应的页码。

数据库索引也是这个道理。它把 user_id 这一列的数据排好序,建成一个"目录"。查询的时候,数据库直接去查目录,定位到数据在哪,不用扫全表。

全表扫描 = 一页一页翻书;索引查询 = 直接翻目录。

差距就是这么来的。

但索引不是越多越好

我一开始以为,那我把所有列都加上索引,是不是就快得飞起?

不行。

索引有代价:

第一,占空间。 每个索引都要存一份数据,列多了,索引能把磁盘撑爆。

第二,拖慢写操作。 你每插入一条数据,数据库都要更新所有相关的索引。索引越多,写入越慢。

第三,用不上的索引白占地方。 有些索引你建了,但查询根本用不到,纯粹浪费。

所以索引的原则是:给经常用来查询的列加索引,别乱加。

尤其是 WHERE、JOIN、ORDER BY 后面经常出现的列,才值得加。

怎么发现该加索引

遇到慢查询,我现在的习惯是:

第一步,看慢查询日志,找出哪条 SQL 慢。

第二步,用 EXPLAIN 看它的执行计划。

EXPLAIN SELECT * FROM orders WHERE user_id = 12345;

如果结果里出现了 type: ALL,说明它在全表扫描,这就是要加索引的信号。

如果出现了 type: ref 或者 type: index,说明它用上了索引,正常。

看 EXPLAIN 是个好习惯,它把数据库"打算怎么执行这条 SQL"告诉你,一眼就能看出问题在哪。

一句话

数据库慢,十次有八次是缺索引。

一条 SQL 从八秒到 0.02 秒,我不是优化了代码,我只是给了它一本目录。

你优化过最爽的一条 SQL 是什么?从多少秒到了多少秒?评论区说说。


本文仅为个人经验分享,具体优化请结合你的实际业务和数据量。