MySQL中BETWEEN
是闭区间,包含边界值
很多人误以为
BETWEEN是“左开右闭”或受NULL影响行为异常,其实它严格等价于
col >= low AND col ,两端都包含。只要<code>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 一样,只要列上有索引,且条件不含函数或表达式,就能走范围扫描(<code>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 ,天然排除<code>NULL值 如果业务需要包含
NULL,必须显式加判断:
WHERE (col BETWEEN 1 AND 10) OR col IS NULL不要依赖
BETWEEN来“过滤掉NULL”,它只是顺带不匹配;真正想排除
NULL,还是明确写
IS NOT NULL更清晰
边界值类型隐式转换、时区上下文、索引生效前提,这三个地方最容易被忽略。写完
BETWEEN语句后,务必用
EXPLAIN看执行计划,并用
SELECT ... LIMIT 5验证实际返回的数据是否符合预期时间/字符范围。
