SQL 错误用法汇总¶
一、WHERE 子句里索引失效¶
1. 对索引列使用函数¶
-- ❌ 不走索引
SELECT * FROM t WHERE DATE(create_time) = '2024-01-01';
-- ✅ 改范围
SELECT * FROM t WHERE create_time >= '2024-01-01' AND create_time < '2024-01-02';
2. 对索引列做运算¶
3. 隐式类型转换¶
-- ❌ phone 是 varchar,传数字
SELECT * FROM t WHERE phone = 13800001111;
-- ✅
SELECT * FROM t WHERE phone = '13800001111';
4. LIKE 以 % 开头¶
全文检索需求用 ES 或全文索引。
5. OR 连接非索引列¶
6. 联合索引不满足最左前缀¶
-- 索引 (a, b, c)
-- ❌
SELECT * FROM t WHERE b = 1;
SELECT * FROM t WHERE c = 1;
-- ✅
SELECT * FROM t WHERE a = 1 AND b = 2;
7. != / NOT IN / NOT EXISTS¶
大多数情况优化器放弃索引,视数据分布而定。
二、SELECT 用法¶
1. SELECT *¶
- 返回不需要的列,浪费 IO。
- 可能无法用覆盖索引。
2. SELECT COUNT(*) 大表实时统计¶
见 count 性能对比。
3. 深分页¶
-- ❌
SELECT * FROM t ORDER BY id LIMIT 1000000, 20;
-- ✅
SELECT * FROM t WHERE id > 1000000 LIMIT 20;
三、JOIN 错误¶
1. JOIN 字段类型不一致¶
a.uid = b.uid,一个是 varchar 一个是 bigint,索引失效。
2. 小表不驱动大表¶
MySQL 优化器通常会选小表驱动,但要注意:被驱动表的 JOIN 字段必须有索引。
3. 过多 JOIN¶
超过 3~5 张表 JOIN 性能急剧下降,应拆分查询或反范式。
四、GROUP BY / ORDER BY¶
1. WHERE 后用 HAVING 过滤¶
-- ❌
SELECT dept, AVG(sal) FROM emp GROUP BY dept HAVING dept = 'IT';
-- ✅
SELECT dept, AVG(sal) FROM emp WHERE dept = 'IT' GROUP BY dept;
2. ORDER BY 字段不在索引里¶
会 filesort,数据量大时慢。
五、其他¶
1. 大事务¶
事务太长,持锁时间久,主从延迟。
2. 循环里执行 SQL¶
// ❌ N+1
for (Order o : orders) {
User u = userMapper.selectById(o.getUserId());
}
// ✅ 一次性 IN 查询
List<User> users = userMapper.selectByIds(
orders.stream().map(Order::getUserId).toList());
3. 大 IN 列表¶
IN (1, 2, ..., 10000) 性能差,分批或临时表。
一句话
索引失效的本质:优化器无法用 B+ 树有序结构快速定位,只能退化为全表扫描。