君哥聊技术

面试官:MySQL BETWEEN AND 语句包括边界吗?

大家好,我是君哥。

使用数据库时,我们经常会用到范围查询,今天来聊一聊 MySQL 的 BETWEEN AND 语句。

1.是否包含边界

为了说明 BETWEEN AND 语句是否包括边界,我们先创建一张表,SQL 如下:

CREATETABLE`test3` (
`id`int(8) NOTNULL AUTO_INCREMENT,
`a`varchar(10) COLLATE utf8_bin DEFAULTNULL,
`b`varchar(10) COLLATE utf8_bin DEFAULTNULL,
`date`dateDEFAULTNULL,
`date_time` datetime DEFAULTNULL,
`time_stamp`timestampNULLDEFAULTNULL,
  PRIMARY KEY (`id`),
KEY`idx_a` (`a`)
) ENGINE=InnoDB AUTO_INCREMENT=11DEFAULTCHARSET=utf8 COLLATE=utf8_bin

我们插入 10 条数据,如下图:

Image

1.1 执行结果

  1. 对 id 做范围查询
SELECT * FROM test3 WHEREidBETWEEN2AND6;

查询结果如下:

Image

可以看到,对 id 做范围查询,包含了边界值 2 和 6,是一个闭区间。

  1. 对 date 做范围查询
SELECT * FROM test3 WHEREDATEBETWEEN'2025-08-28'AND'2025-08-31';

查询结果如下:

Image

可以看到,对 date 类型的字段进行范围查询,同样包含了边界值,是一个闭区间。

  1. 对 date_time 做范围查询
SELECT * FROM test3 WHERE date_time BETWEEN'2025-08-28'AND'2025-08-31';

对 date_time 使用日期做范围查询,查询结果如下:

Image

可以看到,这个查询漏掉了 2025-08-31 这一天的数据,是一个前闭后开的区间。

这是因为 MySQL 会自动将日期的时间部分补充为零点,所以上面的查询语句等价于:

SELECT * FROM test3 WHERE date_time BETWEEN'2025-08-28 00:00:00'AND'2025-08-31 00:00:00';

为了不漏掉数据,可以将上面的查询语句改为:

SELECT * FROM test3 WHEREDATEBETWEEN'2025-08-28'AND'2025-09-01';

对 time_stamp 使用日期做范围查询,结果跟 date_time 一样。

1.2 总结

  1. BETWEEN AND 语句是包括边界值的,是一个前闭后闭的区间。BETWEEN A AND B 等价于 >= A AND <= B。

  2. 注意时间类型的字段,DATETIME 和 TIMESTAMP,如果采用日期格式来查询,结果是前闭后开的区间。BETWEEN A AND B 等价于 >= A AND < B。为了避免漏掉数据,datetime 和 timestamp 使用日期做范围查询,可以在后面的日期上加 1 天。

2.原理

2.1 执行器优化

对于 BETWEEN AND 语句,MySQL 优化器会在早期优化时把它优化成等值查询,所以下面查询 SQL

SELECT * FROM test3 WHERE id BETWEEN 2 AND 6;

在优化器看来完全等价与:

SELECT * FROM test3 WHEREid >= 2ANDid <= 6;

两个 SQL 在性能上没有差别。

2.2 性能

索引范围扫描

如果 BETWEEN AND 语句的字段上有索引,则可以使用索引进行范围扫描,效率很高。我们看一下上面一个 SQL 执行计划如下:

EXPLAINSELECT * FROM test3 WHEREidBETWEEN2AND6;

Imagetype=range,代码使用到了索引进行范围扫描,查询过程如下:

  1. 存储引擎从索引树的根节点开始,找到第一个 id >= 2 的索引条目。这个操作时间复杂度是 O(log n),非常高效;
  2. 从上面找到的第一个索引条目开始,沿着索引树的叶子节点向后顺序扫描;
  3. 当遇到第一个 id > 6 的索引条目时,停止扫描;
  4. 存储引擎给执行器返回结果集。

全表扫描

如果 BETWEEN AND 语句的字段上没有索引,只能进行全表扫描,比如下面的语句:

EXPLAINSELECT * FROM test3 WHERE b BETWEEN30AND50;

我们看一下执行计划:

Image

这就需要扫描表中的每一行记录,逐一判断字段 b 的值是否落在 [30, 50] 这个区间内。这个执行效率非常低。

非主键索引
跟等值查询不同的是,即使 BETWEEN AND 语句的字段加了普通索引,如果查询的字段用不上覆盖索引,也会走全表扫描。如下面的语句:

EXPLAINSELECT * FROM test3 WHERE a BETWEEN30AND50;

虽然字段 a 上面有普通索引,但是查询的是表 test3 中的所有字段,也是走不上 a 这个索引的。我们看一下执行计划:

Image

复合索引

我们再看一下复合索引的情况,我们新建一张表,SQL 如下:

CREATETABLE`test4` (
`id`int(8) NOTNULL AUTO_INCREMENT,
`a`varchar(10) COLLATE utf8_bin DEFAULTNULL,
`b`varchar(10) COLLATE utf8_bin DEFAULTNULL,
`date`dateDEFAULTNULL,
`date_time` datetime DEFAULTNULL,
`time_stamp`timestampNULLDEFAULTNULL,
  PRIMARY KEY (`id`),
KEY`idx_a_b` (`a`, `b`)
) ENGINE=InnoDB AUTO_INCREMENT=11DEFAULTCHARSET=utf8 COLLATE=utf8_bin

在 test4 这张表上,我们建一个字段(a,b)的复合索引。 BETWEEN AND 语句是可以用最左前缀原则的。如果我们执行下面 SQL:

SELECT a,b,id FROM test4 WHERE a BETWEEN2AND6AND b = 3;

复合索引的第一列 a 使用了范围查询,第二列 b 作等值查询。MySQL 可以利用索引快速找到字段 a 在范围[2, 6]之间的数据,然后在这些结果中筛选出 b = 3 的记录。这种情况下字段 a 使用了索引,但是字段 b 没有用上索引。

Image

如果我们执行下面 SQL:

SELECT a,b,id FROM test4 WHERE a = 3 and b BETWEEN2AND6;

复合索引的第一列 a 使用了等值查询,第二列 b 做范围查询。这种情况也是可以走上索引的。

Image

如果我们执行下面 SQL:

SELECT a,b,id FROM test4 WHERE b BETWEEN2AND6;

这种情况不符合最左前缀原则,所以是走不上索引的。

Image

索引下推

使用 BETWEEN AND 语句不能走索引下推。

我们再来创建一张表:

CREATETABLE`test_temp` (
`id`INT(11) NOTNULLDEFAULT'0',
`a`VARCHAR(20) DEFAULTNULL,
`b`VARCHAR(10) DEFAULTNULL,
`c`VARCHAR(10) DEFAULTNULL,
`d`VARCHAR(10) DEFAULTNULL,
  PRIMARY KEY (`id`),
KEY`a_b`(`a`,`b`)
) ENGINE=INNODBDEFAULTCHARSET=utf8

插入几条数据

INSERTINTO test_temp VALUES(100, 10, 20, 2, 1);
INSERTINTO test_temp VALUES(200, 10, 40, 4, 2);
INSERTINTO test_temp VALUES(300, 10, 30, 3, 3);
INSERTINTO test_temp VALUES(400, 40, 10, 1, 4);

如果我们执行下面的 SQL,是不能走索引下推的:

EXPLAINSELECT * FROM test_temp WHERE a BETWEEN'10'AND'50'AND b < '50';

执行计划如下:

Image

而如果我们把 SQL 改成:

EXPLAINSELECT * FROM test_temp WHERE a >= '10'AND a <=  '50'AND b < '50';

执行计划如下:

Image

可以看到,用上了索引下推。

3 总结

本文介绍了 BETWEEN AND 语句的用法、原理和性能,希望对你理解这个范围查询语句有所帮助 。

精品专栏 70 篇,推荐阅读。
又老性能又差,为什么好多公司依然选择 RabbitMQ?

45 个知识点,带你入门消息队列!

引入了 Disruptor 后,系统性能大幅提升!

阿里二面:聊聊 MySQL 主从同步方案的优缺点

面试官:MySQL双主架构有什么优缺点?

面试官:使用 MySQL 时你遇到过哪些索引失效的场景

面试官:MySQL表中有2千万条数据,B+树层高是多少?

面试官:MySQL JOIN 表太多,你有哪些优化思路?

感谢阅读,如果对你有帮助,请点赞和在看。欢迎加我微信:zhujinjun86。

号内回复 seata,下载《阿里分布式中间件Seata从入门到精通》

号内回复 beijing,下载我总结的北京上百家知名科技公司

号内回复 aqs,下载《40张图精通Java AQS》