MySQL BETWEEN 两个日期时间不使用 INDEX

Posted

技术标签:

【中文标题】MySQL BETWEEN 两个日期时间不使用 INDEX【英文标题】:MySQL BETWEEN two datetimes does not use INDEX 【发布时间】:2014-02-24 15:52:21 【问题描述】:
explain
SELECT COUNT(*) AS Count, CreatedBy
FROM `Notes`
INNER JOIN Users ON UserID = CreatedBy
INNER JOIN UserRoles ON URoleID = RoleID AND RoleID = 1
WHERE NoteVisible = 1 AND NoteText NOT LIKE '%SOME KEYWORD%' 
      AND Created BETWEEN '2014-02-24 00:00:00' AND '2014-02-24 23:59:59' 
GROUP BY CreatedBy

如您所见,ref 为 NULL,并且经过 23 行,而不仅仅是经过 1 行。现在对于这个例子来说这很快,但是当我做 1-2 个月的范围时,行变成 >10000 并且它减慢了页面并锁定了表格。

注意如果我删除 00:00:0023:59:59 然后它使用索引它只经过 1 行但我需要选择从 00:00 开始到 23:59 结束的一整天的所有数据。

请帮助我重组此查询以解决此问题或提出任何可能的解决方案。谢谢。

编辑

BETWEEN 替换为 >>=没有解决问题

【问题讨论】:

如果用BETWEEN 代替('2014-02-24' <= Created AND Created < '2014-02-25') 会怎样? 已经在不同的变体中这样做了仍然不使用索引 请贴出表的结构,或者至少给查询中的列名加上前缀,很难猜出哪个列属于哪个表。 NoteVisible 是否属于 Notes 是 NoteVisible 属于笔记,为什么它会属于任何呈现的表格? 【参考方案1】:

此查询使用索引。 选择类型为range,使用的键为Created 对于范围类型,ref 列始终为空, 参考文档:http://dev.mysql.com/doc/refman/5.7/en/explain-output.html#jointype_range

范围

仅检索给定范围内的行,使用索引选择行。输出行中的键列指示使用了哪个索引。 key_len 包含已使用的最长密钥部分。 此类型的 ref 列为 NULL。

(强调我的)

【讨论】:

但如果我删除说明它只返回 1 行,则该范围内没有 23 行。 这只是一个估计——MySql 认为有 23 行。它不会在解析阶段检查确切的行数,它只是估计。但考虑到这一点,它认为使用该索引并连接 23 行比使用主键连接 X 行更好。 有没有办法解决减速问题?【参考方案2】:

当您在大于/小于比较中将日期时间字段与字符串进行比较时。如果您使用强制转换或函数(如 UNIX_TIMESTAMP())并将其他日期转换为 unixtimestamp,则可以解决问题,但会破坏索引的使用。也许更好的解决方案是将日期作为unix时间戳存储在表中并在其上放置索引。

另一种方式,你可以在你的 sql 中添加“限制”也对我有用

【讨论】:

以上是关于MySQL BETWEEN 两个日期时间不使用 INDEX的主要内容,如果未能解决你的问题,请参考以下文章

mysql如何查某年某月至某年某月的数据,没有日?

MySQL BETWEEN 语法

使用 mySQL 运算符 BETWEEN 和经典日期间隔之间有啥区别? [复制]

mysql如何查询两个日期之间最大的连续登录

Mysql: mysql between 日期索引 索引问题-日期索引使用

BETWEEN 两个日期与函数 SQL