如何让 SQL 跑快一点?
同学们,今天老韩跟你们聊点硬核的——SQL 优化。别一听到“SQL优化”就头大,其实它就是个朴实无华又枯燥的技能,但偏偏是这个技能,决定了你的数据库是“跑得飞快”,还是“跛着脚走”。
很多同学平时写 SQL,只求能跑就行,从来不关心它快不快,甚至觉得“数据库慢是 DBA 的事儿,跟我写的 SQL 没关系”。这种想法真是要不得啊!SQL 跑得慢,99% 的锅在代码,而不是 DBA。
今天老韩就带你们好好剖一剖,为什么 SQL 跑得慢?我们又该怎么让它快一点? 文章有点长,但干货满满,看完保准刷新你的数据库认知。
别让“全表扫描”拖死你
SQL 跑得慢,全表扫描绝对是罪魁祸首之一。
啥叫全表扫描?简单来说,就是数据库为了执行你的查询,把表里所有的数据一条条地过一遍,直到找到满足条件的那几条。你可以想象一下,这就像翻阅一个十万页的书,你只是想找个目录,但硬生生翻完了整本书,怎么可能快?
举个例子,你写了这么一条 SQL:
SELECT * FROM users WHERE age = 25;
表 users 有一百万条记录,但你居然没给 age 加索引,数据库只能从头到尾一行行扫。这时候,你就别怪它慢了,问题根本出在你自己身上。
怎么解决全表扫描?
很简单,给查询条件上的字段加索引。 索引就像书的目录一样,能快速定位你需要的数据,大大减少扫描的范围。
但同学们注意,索引不是乱加的!如果表里就三五百条数据,加索引意义不大,反而会拖慢写入速度。索引适用于大表,尤其是查询频繁的字段。
索引有了,为什么还慢?
有同学可能会问:“老韩,我的字段已经加了索引,为什么查询还是慢?”
这就引出了一个经常被忽略的问题:索引没用起来。
你知道吗,索引不是摆设,但你写 SQL 的方式决定了数据库能不能用上它。以下几种操作,都会让索引失效:
1. 对索引字段做了计算或函数操作
比如你写了这样一条 SQL:
SELECT * FROM users WHERE YEAR(birth_date) = 1995;
这里 YEAR(birth_date) 是对字段的函数操作,数据库会直接放弃用索引,改成全表扫描。正确的写法应该是:
SELECT * FROM users WHERE birth_date BETWEEN '1995-01-01' AND '1995-12-31';
2. LIKE 模糊匹配带前置通配符
比如你写了这样一条 SQL:
SELECT * FROM products WHERE name LIKE '%phone';
因为 % 在前,数据库没法用索引,只能逐条扫描。正确的做法是避免 % 开头,改成:
SELECT * FROM products WHERE name LIKE 'iPhone%';
3. 隐式类型转换
如果你表里的 id 是字符串类型,而你用数字去比较:
SELECT * FROM users WHERE id = 123;
数据库会先把所有的 id 转成数字,然后比较,索引直接失效。正确做法是保持类型一致:
SELECT * FROM users WHERE id = '123';
索引是把“双刃剑”,用得好是利器,用不好就是摆设。记住,写 SQL 要尽量“贴合”索引,让它能发挥作用。
慎用 SELECT *,别要一大堆无用数据
还有一个让 SQL 慢得哭笑不得的原因,就是你贪得无厌,总想一次查太多数据。
很多同学写查询,喜欢用 SELECT *,比如:
SELECT * FROM users WHERE age > 25;
* 代表把表里所有字段都查出来。问题是,你真的需要所有字段吗?比如这个表里有 50 个字段,其中还包括几个超大字段(比如存图片的 blob),查询的时候全都带上,这不是找慢吗?
老韩建议:
• 查询时只取需要的字段,比如:
SELECT id, name, email FROM users WHERE age > 25;
• 如果表太大,字段太多,可以考虑拆表,把常用字段放在一个“小表”里,减少查询成本。
别让你的 SQL 成为数据库的“背锅侠”,要的数据就拿,不要的数据一个字别动。
LIMIT 和分页,别乱用
分页查询是 web 开发的常见操作,但你知道吗,分页查询用不好,会让数据库累得半死。
比如你写了这样一条分页查询:
SELECT * FROM articles ORDER BY publish_date DESC LIMIT 10000, 10;
LIMIT 10000, 10 的意思是跳过前一万条记录,取接下来的 10 条。问题来了,为了跳过那一万条数据,数据库其实还是得扫一遍,然后丢掉前面的一万条,效率极低。
怎么优化分页查询?
• 改用“基于主键”的方式分页,比如:
SELECT * FROM articles WHERE id > 10000 LIMIT 10;
这样数据库能直接从主键索引找到目标数据,而不用扫描无用的记录。
• 如果必须用 LIMIT,尽量限制页码范围,避免翻到特别靠后的页。
分页是高频操作,写得好坏,直接影响数据库的性能。
JOIN 查询,先把逻辑捋清楚
很多同学喜欢写复杂的多表查询,结果 SQL 慢得像老牛拉车。JOIN 查询性能差,大多是因为你没捋清楚逻辑。
比如你写了这样一条 SQL:
SELECT *
FROM orders
JOIN customers ON orders.customer_id = customers.id
WHERE customers.age > 30;
问题是,表 orders 有几百万条记录,customers 也有几十万条,你一 JOIN,数据库的临时表可能大得吓人。如果加上筛选条件写得不好,查询时间分分钟上天。
优化 JOIN 的方法有两个关键点:
1. 确保 JOIN 的字段有索引,比如 customer_id 和 id;
2. 把筛选条件提前,比如可以改成:
SELECT *
FROM orders
JOIN (SELECT id FROM customers WHERE age > 30) AS filtered_customers
ON orders.customer_id = filtered_customers.id;
这样可以先把 customers 的筛选范围缩小,减少 JOIN 的数据量。
心理按摩:慢 SQL 没那么可怕
老韩最后想给你们点心理按摩:SQL 慢不是你的原罪,但不优化就是。
很多慢 SQL 的问题,表面上看是“数据库性能差”,但实际上是你写 SQL 时不够细心。慢 SQL 不可怕,只要你愿意花时间优化,每个小细节都可能让它跑得飞快。
优化 SQL 不是一蹴而就的事,它考验的是你对数据库原理的理解、对数据结构的敏感度,以及对性能问题的责任感。只要你愿意学、愿意改,慢 SQL 会变成快 SQL,你也会成为更牛的程序员。
最后送你们一句话:“写好 SQL,不只是技术,更是对职业的尊重。” 让 SQL 跑快一点,从今天开始吧!