大家好,我是小耶。前面两周讲了各种慢查询案例,今天不展开新知识点,只总结三个最实用的“肌肉记忆”。不是我编的,是我踩坑踩出来的。
1 肌肉记忆一:WHERE条件里的字段绝不“加工”
核心:索引列保持原样,不做任何变换。
| 错误写法 | 正确写法 | 原理 |
|---|---|---|
WHERE DATE(order_date) = '2026-05-01' |
WHERE order_date >= '2026-05-01' AND order_date < '2026-05-02' |
函数让索引失效,改范围查询 |
WHERE price + 10 > 100 |
WHERE price > 90 |
运算移到右边 |
WHERE phone = 13812345678(phone是varchar) |
WHERE phone = '13812345678' |
类型不匹配触发隐式转换 |
养成习惯:写完WHERE条件后,检查等号左边有没有函数、运算或类型不一致。
2 肌肉记忆二:存在性检查用EXISTS,别滥用IN或JOIN+DISTINCT
很多新人看到“查A表中存在于B表的数据”,第一反应是IN或JOIN。但在MySQL中,EXISTS通常是最优解:
-- ✅ 推荐写法(存在性检查)
SELECT * FROM users u
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.user_id);
-- ❌ 可能有临时表开销的写法
SELECT DISTINCT u.* FROM users u JOIN orders o ON u.user_id = o.user_id;
为什么?EXISTS一旦在内层找到匹配就立即停止扫描,且不需要生成去重临时表。JOIN可能产生重复行,必须加DISTINCT,而DISTINCT在大表上可能创建磁盘临时表,反而更慢。
什么时候用JOIN? 需要同时返回两张表的字段时。单纯判断存在,无脑用EXISTS。
3 肌肉记忆三:分页和批量操作必须“刹车”
3.1 分页不用 LIMIT M,N 深分页
-- ❌ 深分页:扫描100万行再取10行
SELECT * FROM orders ORDER BY id LIMIT 1000000, 10;
-- ✅ 游标分页:记录上一页最后id
SELECT * FROM orders WHERE id > 上一页最大id ORDER BY id LIMIT 10;
3.2 批量删除/更新一次不超过1000行
-- ❌ 一次性删除几百万行,长事务锁表
DELETE FROM logs WHERE created_at < '2025-01-01';
-- ✅ 分批删除,循环执行
DELETE FROM logs WHERE created_at < '2025-01-01' LIMIT 1000;
3.3 修改数据前,先 SELECT 验证影响行数
BEGIN;
SELECT COUNT(*) FROM orders WHERE status = '测试';
-- 确认行数正确再执行
DELETE FROM orders WHERE status = '测试';
COMMIT;
4 总结:三个习惯能让你避免多少坑?
- 不对WHERE字段“加工”:避免90%的索引失效问题。
- 存在性检查用EXISTS:避免不必要的JOIN + DISTINCT临时表开销。
- 分页+批量加“刹车”:避免深分页、长事务、锁表事故。
这些都不是高深理论,而是每次写SQL时多看一眼就能做到的事。养成肌肉记忆,你的代码会更稳,加班会更少。
小耶在手,SQL 不愁。
还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽……我们下次见~