SELECT order_id, order_no, total_amount, created_at FROM orders WHERE user_id = 1001;
为什么这件事很重要?
因为数据库的性能问题,很多时候不是“算得太慢”,而是“搬得太多”。
你以为自己只是多拿了几列,数据库看到的是:
• 更多页读取
• 更大结果集
• 更重排序/回表成本
• 更差缓存命中率
一句话: 是小项目的朋友,大表时代的敌人。
2. WHERE 条件对字段做函数运算
很多人写条件时,喜欢直接对列做处理:
SELECT * FROM orders WHERE DATE(created_at) = '2026-03-26';
这类写法语义上没错,但性能上很容易出事。
因为当你对索引列做函数计算时,数据库往往没法直接利用索引,最后就可能退化成全表扫描。
更好的写法是改成范围查询:
SELECT order_id, user_id, created_at FROM orders WHERE created_at >= '2026-03-26 00:00:00' AND created_at < '2026-03-27 00:00:00';
记住一个简单原则
尽量别动列,去动常量。
也就是说,别让数据库先把每一行都加工一遍,再比较;而是把边界算好,直接去命中索引。
这类错误在以下场景尤其常见:
• DATE(create_time)
• YEAR(order_time)
• SUBSTRING(phone, 1, 3)
• UPPER(name)
看着优雅,跑起来经常像灾难片。
3. 模糊查询一上来就是前缀 %
比如:
SELECT * FROM users WHERE name LIKE '%周%';
这类查询在搜索场景很常见,但一旦前面加了 %,普通索引通常就很难用了。
结果就是:扫全表,然后一行一行比。
如果你的表有几百万数据,这种写法就不再是“能跑”,而是“谁写的,出来挨打”。
怎么改?
要看业务目标:
情况一:前缀匹配
SELECT user_id, name FROM users WHERE name LIKE '周%';
这种更有机会走索引。
情况二:全文搜索需求
如果你真的是要“包含某关键词”,别硬拿普通 LIKE '%xxx%' 扛所有搜索需求。
更合理的方向通常是:
• 全文索引
• 搜索引擎(如 Elasticsearch)
• 额外搜索字段 / 倒排方案
数据库不是不能搜,但你别拿它当全文检索引擎往死里打。
4. IN、OR、联表条件乱写,结果把执行计划写崩了
很多 SQL 慢,不是因为数据库不够强,而是因为你把优化器逼疯了。
例如:
SELECT * FROM orders WHERE status = 'PAID' OR user_id = 1001;
再比如:
SELECT * FROM orders WHERE id IN (1,2,3,4,5,...一大串...);
或者联表时条件不清晰:
SELECT * FROM orders o JOIN users u ON o.user_id = u.id WHERE o.created_at >= '2026-01-01';
表面看都合法,实际上可能导致:
• 走不上理想索引
• 连接顺序变差
• 中间结果集过大
• CPU 飙升
更靠谱的思路
• 大量 IN 值,考虑临时表 / 批量表驱动
• OR 条件复杂时,考虑拆成 UNION ALL
• 联表前先过滤小结果集
• 别默认“SQL 能运行 = SQL 写得对”
例如把 OR 拆开:
SELECT order_id, user_id, status FROM orders WHERE status = 'PAID' UNION ALL SELECT order_id, user_id, status FROM orders WHERE user_id = 1001 AND status <> 'PAID';
不一定每次都要这么写,但你至少得知道:
复杂条件不是不能写,而是不能闭着眼乱写。
5. 分页永远只会写 LIMIT 100000, 20
这也是经典事故现场。
SELECT * FROM orders ORDER BY id LIMIT 100000, 20;