前两天我们组小李上线一条 SQL,线上 CPU 直接飙满,大家差点以为被黑了。最后一查,居然是那种看似无害、但性能堪比“挖矿”的写法。今天我就来总结下这八种“坑死同事”的 SQL 写法,都是实战踩出来的坑,真·血泪史。
1. where 里动不动加函数,索引直接废了
比如小李写的这个:
SELECT * FROM user WHERE DATE(create_time) = '2025-10-20';
这看着没毛病对吧?但问题是你一旦在列上用了函数,create_time的索引就失效了,MySQL 只能全表扫描。几百万行数据那性能可想而知。
正确写法:
SELECT * FROM user WHERE create_time >= '2025-10-20 00:00:00'
AND create_time < '2025-10-21 00:00:00';
Java 里写的时候别偷懒:
String sql = "SELECT * FROM user WHERE create_time >= ? AND create_time < ?";
ps.setTimestamp(1, Timestamp.valueOf("2025-10-20 00:00:00"));
ps.setTimestamp(2, Timestamp.valueOf("2025-10-21 00:00:00"));
2. 模糊查询“百分号”放错位置
SELECT * FROM product WHERE name LIKE '%耳机';
前面加%,索引直接罢工。除非真的要模糊匹配,否则改成:
SELECT * FROM product WHERE name LIKE '耳机%';
如果一定要前模糊,那就老老实实加个全文索引或者用 ES 吧。
3. in 里放几千个值,慢得像回表取快递
这是真实事故:测试写了个WHERE id IN (1,2,3,...3000),结果 MySQL 直接跑了 8 秒。
原因?优化器懵了,它得一条条匹配。改成临时表关联,立刻快成闪电。
SELECT u.* FROM user u
JOIN temp_ids t ON u.id = t.id;
Java 里可以这样搞:
jdbcTemplate.batchUpdate("INSERT INTO temp_ids(id) VALUES (?)", ids);
4. order by + limit 没索引,分页翻页越翻越慢
经典分页坑:
SELECT * FROM log ORDER BY create_time DESC LIMIT 10000, 20;
越往后翻越慢,因为 MySQL 要先扫出 10020 条,再扔掉前 10000 条。
改法:
SELECT * FROM log
WHERE create_time < ?
ORDER BY create_time DESC
LIMIT 20;
Java 里用上一次的最大时间点作为游标:
String sql = "SELECT * FROM log WHERE create_time < ? ORDER BY create_time DESC LIMIT 20";
ps.setTimestamp(1, lastTime);
5. count(*) 统计大表还带 where,直接拖垮 CPU
SELECT COUNT(*) FROM order WHERE status = 1;
如果表里几千万行,这句能让 DBA 一夜无眠。 解决办法有两个:
建个状态计数表,每次更新同步;
或者用索引覆盖查询:
SELECT COUNT(status) FROM order WHERE status = 1;
注意:COUNT(status)在 status 非空时能走索引。
6. 随手 join,不写 on 条件,炸库必备
这种写法真是新手杀:
SELECT * FROM user u JOIN order o;
结果就是笛卡尔积,几百万行对几百万行,服务器直接趴。
正确写法永远加ON:
SELECT * FROM user u
JOIN order o ON u.id = o.user_id;
7. NULL 参与比较,结果让人怀疑人生
SELECT * FROM employee WHERE salary != 10000;
如果 salary 里有 NULL,这行数据不会被选中。 因为在 SQL 世界里,NULL != 10000也是NULL。
正确写法:
SELECT * FROM employee WHERE salary IS NULL OR salary != 10000;
8. select * 万能选手,IO 压力爆炸
别再用SELECT *了,尤其是在表字段几十个的那种表。 IO、网络、内存,全浪费。
指定字段才是王道:
SELECT id, username, email FROM user WHERE status = 1;
Java ORM 框架也能限制字段:
@Query("SELECT u.id, u.username FROM User u WHERE u.status = 1")
List<UserDTO> findActiveUsers();
总结
SQL 不怕写慢,怕的是“不知道为什么慢”。 很多坑不是 SQL 本身复杂,而是那些看似小小的“习惯问题”。 所以每次写 SQL 前,脑子里过一遍:能走索引吗?能少扫描吗?能提前过滤吗?
少一点想当然,多一点怀疑精神。 毕竟,你写的每一条 SQL,可能都是 DBA 的眼泪。