应使用EXISTS替代IN:因IN遇NULL失效,而EXISTS逻辑清晰且可利用联合索引;SQL Server和Oracle对IN中NULL更严格,MySQL行为不稳定,故统一用EXISTS。

WHERE子句里用BETWEEN还是>= AND
直接说结论:优先用 >= AND ,别迷信 BETWEEN。它在边界值处理上容易出错,尤其涉及时间戳或字符串时。
常见错误现象:BETWEEN '2023-01-01' AND '2023-01-31' 看似覆盖整月,但若字段是 DATETIME 类型,实际只查到 '2023-01-31 00:00:00',漏掉当天其余时间的数据。
>= '2023-01-01' AND 更精确,且能利用索引(左闭右开区间天然适配B+树范围扫描)- 字符串比较时,
BETWEEN 'a' AND 'm'会包含'mzzz'这类意外值,而>= 'a' AND 同样有风险,应明确长度或用前缀约束 - 所有数据库都支持
>= AND ,但BETWEEN在某些嵌套子查询中可能被优化器误判为不可下推条件
子查询结果当表用时,必须显式命名(MySQL/PostgreSQL都报错)
嵌套查询做区间统计时,常把子查询当临时表 JOIN 或 WHERE IN,但忘了给它起别名——这是语法硬伤,不是风格问题。
错误示例:SELECT * FROM orders WHERE order_date IN (SELECT create_time FROM logs WHERE type='pay') 看似没问题,但一旦加了 GROUP BY 或想对子查询结果再筛选,就必须包装成派生表。
- 正确写法:
SELECT o.* FROM orders o JOIN (SELECT DISTINCT create_time FROM logs WHERE type='pay') AS t ON o.order_date >= t.create_time AND o.order_date - MySQL 5.7+ 和 PostgreSQL 要求所有子查询出现在
FROM子句时必须带AS alias,否则直接报错Every derived table must have its own alias - 别名不能是保留字,比如
AS order或AS group会失败;建议统一用t、src、bound这类无歧义缩写
用窗口函数替代自连接做滚动区间统计(避免笛卡尔积爆炸)
想算“过去7天订单总额”,有人写 JOIN orders o1 ON o1.order_date BETWEEN DATE_SUB(o2.order_date, INTERVAL 6 DAY) AND o2.order_date —— 数据量一过万就卡死。
本质是用自连接模拟滑动窗口,复杂度 O(n²),而窗口函数是 O(n) 且语义清晰。
- 推荐写法:
SELECT order_date, SUM(amount) OVER (ORDER BY order_date RANGE BETWEEN INTERVAL 6 DAY PRECEDING AND CURRENT ROW) AS sum_7d FROM orders -
RANGE按值范围(适合日期/数字),ROWS按行数(适合固定条数),别混用;PostgreSQL 支持INTERVAL,MySQL 8.0+ 仅支持ROWS,需改用DATE_SUB配合变量模拟 - 注意 NULL 值:如果
order_date允许为空,RANGE窗口会跳过这些行,但不会报错,容易造成统计偏差
EXISTS比IN更适合大表区间关联(尤其子查询含NULL时)
当主表百万级、子查询结果可能含 NULL,用 IN 会导致整个条件恒为 UNKNOWN,查不到任何数据——这是最隐蔽的坑。
典型场景:查“在活跃用户区间内下单的客户”,子查询从日志表取最近登录时间,但部分用户没登录记录,返回 NULL。
-
WHERE user_id IN (SELECT user_id FROM login_log WHERE login_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)):只要子查询结果含一个NULL,整条IN判断失效 - 换成
EXISTS:WHERE EXISTS (SELECT 1 FROM login_log l WHERE l.user_id = orders.user_id AND l.login_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)),逻辑清晰,且能走user_id + login_time联合索引 - SQL Server 和 Oracle 对
IN的 NULL 处理更严格,MySQL 默认宽松但行为不稳定,一律按EXISTS写
事情说清了就结束。区间统计真正难的不是语法,而是搞清你的数据有没有空值、时区怎么对齐、索引能不能覆盖到边界表达式——这些不看执行计划根本发现不了。










