日期时间字段上的 MySQL 索引不是 RANGE 类型,而是使用 INDEX 类型

Posted

技术标签:

【中文标题】日期时间字段上的 MySQL 索引不是 RANGE 类型,而是使用 INDEX 类型【英文标题】:MySQL index on datetime field not going RANGE type, instead is using INDEX type 【发布时间】:2020-04-23 13:44:24 【问题描述】:

我想知道为什么RANGE类型中没有使用这个索引,而是INDEX

索引:

CREATE INDEX myindex ON orders(order_date);

查询:

EXPLAIN 
SELECT order_date FROM orders 
WHERE order_date BETWEEN '2020-01-01 00:00:00' AND '2020-12-31 23:59:59';

在输出中,TYPE 列设置为 INDEX。在我看来,它应该在索引中找到日期大于第一个的记录,然后通过链表,但如果是这种情况,类型应该是range,而不是INDEX

另外,同样在from子句上使用force index(report_ordini_per_utente_in_un_periodo) ,类型还是index

我正在使用 MariaBD 10.1.43

【问题讨论】:

我的 mysql 5.7 和 MadiaDB 10.1 都有“范围”。能否提供 show create table 输出? 只是一个日期时间字段 您的意思是表中只有一个日期时间列? @fifonik 是的,“order_date”只是一个日期时间,请查看我自己的答案并尝试检查您的版本中是否也有这种行为 对我来说,索引时日期时间不是范围是合乎逻辑的,因为它不是唯一索引。假设你有 3 个日期相似(在这种情况下它是范围的右边缘),那么从这 3 个中,你认为哪一个是实际数据范围的边缘?你不能说。 【参考方案1】:

您提供的查询只有一列。该列在索引中。所以,索引是“覆盖”的。因此EXPLAIN 会说Using index

表格中的日期范围是多少?

如需进一步讨论,请提供SHOW CREATE TABLE 和所有EXPLAIN 输出。你的散文中可能会遗漏一些微妙的东西。

【讨论】:

好吧,我认为该表的列数并不相关,但是,mariadb 似乎选择使用整个索引,因为没有那么多记录,所以可能更容易扫描整个索引,而不是使用二进制搜索来查找第一个(但是日期分布在整个 2019 年) 列数有很大的不同。只有一列——与ORDER BY 列相同——查询可以完全在索引的BTree 中运行。如果在SELECT 中添加另一列,查询计划会发生变化,查询会运行得更慢。 @AlbertoSinigaglia - 查找第一个数据的“向下钻取”是整个查询中相对微不足道的部分。您说日期分布在 2019,但查询只要求 2020。我正在寻找是否涉及很多行,或者可能没有。 好吧,假设他们是在 2020 年,我这边运行的查询是搜索记录的年份【参考方案2】:

原来是一种错误,因为我在数据库中的所有记录都在该范围内,因此它显然必须遍历整个索引,这就是为什么它将 TYPE 标记为 @987654322 @ 而不是 RANGE。更奇怪的是,假设查询有order_date between X and Y,如果所有记录的日期都大于X,但并非所有记录的日期都小于Y,它也将其标记为INDEX而不是RANGE

【讨论】:

猜测:从头开始可能会有所不同。

以上是关于日期时间字段上的 MySQL 索引不是 RANGE 类型,而是使用 INDEX 类型的主要内容,如果未能解决你的问题,请参考以下文章

日期字段上的 Postgres DESC 索引

用mysql查询某字段是不是有索引怎么做?

在mysql中索引日期时间字段是个好主意吗?

在 MySQL 中的日期字段上放置索引

时间戳列上的 MySQL 索引不用于大日期范围

MySQL 优化器之Index merge Multi-Range Read MRR与Batched Key Access使用案例详解