在业务系统中,一条写得不好的SQL可能让接口从几十毫秒变到十几秒。下面用几个常见例子说明怎么把慢查询改快,不需要高深理论,照着做就能见效。

一、为过滤字段建立索引
最常见的问题是where条件里的字段没有索引,导致数据库只能全表扫描。假设有用户表user,里面有一百万行数据,我们经常按手机号查用户。
未优化的查询
SELECT id, name, phone FROM user WHERE phone = '13800000000';
如果phone字段没有索引,数据库会逐行比对。我们用explain看计划,会看到type为ALL。建立索引后情况不同。
优化方式
CREATE INDEX idx_phone ON user(phone);
再次执行同样的查询,explain里type变成ref,扫描行数从一百万降到一行左右。
二、避免对索引列使用函数
有些同学喜欢在where里对字段套函数,这会让索引失效。
错误写法
SELECT id FROM order_table WHERE DATE(create_time) = '2023-05-01';
这里DATE函数作用在create_time上,即便有索引也用不上。改成范围查询即可走索引。
正确写法
SELECT id FROM order_table WHERE create_time >= '2023-05-01 00:00:00' AND create_time < '2023-05-02 00:00:00';
三、用join代替子查询
子查询在有些数据库里会被重写成临时表,开销大。比如要查有订单的用户。
子查询写法
SELECT name FROM user WHERE id IN (SELECT user_id FROM order_table);
join写法
SELECT DISTINCT u.name FROM user u JOIN order_table o ON u.id = o.user_id;
在多数情况下,join可以利用两端的索引,比IN子查询更快。可以用下表快速对照:
| 场景 | 慢写法 | 快写法 |
|---|---|---|
| 按字段查 | 无索引全扫 | 建索引 |
| 时间过滤 | 套函数 | 范围查询 |
| 存在判断 | IN子查询 | JOIN |
四、只查需要的列
用SELECT *会读出所有字段,增加IO和内存。明确列出字段名,配合覆盖索引效果更好。
-- 不好 SELECT * FROM user WHERE id = 1; -- 好 SELECT id, name FROM user WHERE id = 1;
五、小结
优化SQL的核心思路是减少扫描行数、让索引生效、减少不必要的数据传输。以上例子都很简单,但覆盖了大部分日常慢查询的原因。写完后用explain验证,比凭感觉改更可靠。