BETWEEN是闭区间,包含边界值,严格等价于col >= low AND col

MySQL中BETWEEN是闭区间,包含边界值
很多人误以为BETWEEN是“左开右闭”或受NULL影响行为异常,其实它严格等价于col >= low AND col ,两端都包含。只要low和high可比较、类型兼容,且不为NULL,结果就确定。
常见错误现象:
- 写成
WHERE id BETWEEN 10 AND 5——MySQL会自动交换顺序,仍返回5 ,但语义混乱,应避免 - 用
WHERE date_col BETWEEN '2023-01-01' AND '2023-01-01'查单日数据——它能命中当天00:00:00,但漏掉当天其他时间点(除非date_col是DATE类型) - 对
TEXT或JSON列直接用BETWEEN——可能触发隐式转换或全表扫描,性能差
BETWEEN和>=/在索引使用上完全等价
优化器对BETWEEN的处理和显式写col >= a AND col 一样,只要列上有索引,且条件不含函数或表达式,就能走范围扫描(type: range)。
实操建议:
- 检查执行计划:
EXPLAIN SELECT * FROM orders WHERE created_at BETWEEN '2024-01-01' AND '2024-01-31';
确认key字段非NULL,rows量级合理 - 如果
created_at是DATETIME,想查2024年1月整月,必须写成BETWEEN '2024-01-01 00:00:00' AND '2024-01-31 23:59:59',或更安全地用>= '2024-01-01' AND - 复合索引中,
BETWEEN只能用于最左前缀的连续部分。例如索引(a, b, c),WHERE a = 1 AND b BETWEEN 2 AND 4可用索引,但WHERE a > 1 AND c BETWEEN 10 AND 20无法利用c的索引
字符串和日期用BETWEEN要特别注意排序规则和精度
字符串比较依赖当前列的collation,比如utf8mb4_0900_as_cs区分大小写和重音,而utf8mb4_general_ci不区分。这直接影响BETWEEN 'a' AND 'z'是否包含'Z'或'é'。
日期时间类型更要小心:
-
DATE列:直接BETWEEN '2024-01-01' AND '2024-01-01'没问题,精确到日 -
DATETIME或TIMESTAMP列:同上写法只匹配00:00:00这一秒,几乎必然为空 - 时区问题:
TIMESTAMP存的是UTC,但BETWEEN字面量按会话时区解析。例如会话在+08:00,BETWEEN '2024-01-01' AND '2024-01-01'实际查的是UTC的2023-12-31 16:00:00到2024-01-01 16:00:00
遇到NULL时BETWEEN直接返回UNKNOWN
这是SQL三值逻辑的体现:NULL BETWEEN 1 AND 10既不是TRUE也不是FALSE,而是UNKNOWN,所以该行不会出现在查询结果中——和WHERE子句里所有UNKNOWN都被过滤掉一致。
这意味着:
-
WHERE col BETWEEN 1 AND 10等价于WHERE col >= 1 AND col ,天然排除NULL值 - 如果业务需要包含
NULL,必须显式加判断:WHERE (col BETWEEN 1 AND 10) OR col IS NULL - 不要依赖
BETWEEN来“过滤掉NULL”,它只是顺带不匹配;真正想排除NULL,还是明确写IS NOT NULL更清晰
边界值类型隐式转换、时区上下文、索引生效前提,这三个地方最容易被忽略。写完BETWEEN语句后,务必用EXPLAIN看执行计划,并用SELECT ... LIMIT 5验证实际返回的数据是否符合预期时间/字符范围。










