mysql中日期条件如何查询速度有区别吗

无索引,TO_DAYS 函数更快;
使用索引时, time_column > '2024-01-01 00:00:00' 更快。

问题起源

在mysql查询条件中,经常遇到时间限制的查询,比如查询一个时间段内的数据,或者查询某一天的数据:

1
SELECT * FROM table WHERE createtime >  '2019-01-01 00:00:00' AND createtime < '2019-01-01 23:59:59'

还有另外一种查询方法是:

1
SELECT * FROM table WHERE TO_DAYS(createtime) = TO_DAYS('2019-01-01 00:00:00')

两种查询方式是否有区别呢?TO_DAYS的查询方式是否比较快呢?

文档查看

  1. 关于DATETIME字段类型,官网是这么解释的:

The DATETIME type is used for values that contain both date and time parts. MySQL retrieves and displays DATETIME values in ‘YYYY-MM-DD hh:mm:ss’ format. The supported range is ‘1000-01-01 00:00:00’ to ‘9999-12-31 23:59:59’.

即datetime包括日期与时间两部分,以格式为YYYY-MM-DD hh:mm:ss的来检索与显示,表示范围为:1000-01-01 00:00:009999-12-31 23:59:59

  1. 关于函数TO_DAYS(DATE)

TO_DAYS()
返回日期和年份0之间的天数,注:只能用于公历中的日期
例如:

1
SELECT TO_DAYS("0000-01-01") 

执行结果为:1。

实际测试

我们创建一个含有700万数据的表进行实际的测试:

现在我们已经有了一个表test_table,但是这个表里没有时间字段,我们添加字段,并设置随机日期值:

1
2
3
4
5
6
7
UPDATE `test_table`
SET createtime = FROM_UNIXTIME(
1672502399 - (
FLOOR(1 +(RAND() * 12)) * 2678400
) - (FLOOR(1 +(RAND() * 31)) * 86400) - FLOOR(1 +(RAND() * 86400)),
'%Y-%m-%d %H:%i:%s'
)

其中,部分日期的随机结果如下:

2024-03-20-13-04-03-20240320130402

我们首先通过Group by 来看看日期的年份数据范围:

1
2
3
4
5
6
7
SELECT
DATE_FORMAT(createtime, '%Y'),
COUNT(*)
FROM
`test_table`
GROUP BY
DATE_FORMAT(createtime, '%Y')

执行结果为:

年份 数据量
2021 749087
2022 6392067

按照月份统计:

1
2
3
4
5
6
7
SELECT
DATE_FORMAT(createtime, '%Y-%m') as month,
COUNT(*)
FROM
`test_table`
GROUP BY
DATE_FORMAT(createtime, '%Y-%m')

2024-03-20-13-04-44-20240320130443

因为我们测试的是TO_DAYS,所以我们还需要查看具体日期的分布情况,以便于比较:

1
2
3
4
5
6
7
SELECT
DATE_FORMAT(createtime, '%Y-%m-%d'),
COUNT(*)
FROM
`test_table`
GROUP BY
DATE_FORMAT(createtime, '%Y-%m-%d')

2024-03-20-13-05-10-20240320130509

无索引

测试同一天查询速度:

使用日期直接比较:

1
2
3
4
5
6
7
SELECT
*
FROM
`test_table`
WHERE
createtime > '2021-11-24 00:00:00'
AND createtime < '2021-11-24 23:59:59'

上述语句执行时间3次的实际执行结果分别为:2.358s, 2.361s,2.369s

使用TO_DAYS判等:

1
2
3
4
5
6
SELECT
*
FROM
`test_table`
WHERE
TO_DAYS(createtime) = TO_DAYS('2021-11-24 00:00:00')

使用TO_DAYS执行3次,执行时间分别为:1.944s,1.954s,1.929s

在对比列没有添加索引的情况下,通过时间对比函数TO_DAYS速度更快!

我们分别使用Explain来看一下两句SQL:

直接比较:

2024-03-20-13-05-49-20240320130548

TO_DAYS判等:

2024-03-20-13-06-07-20240320130606

两者的区别在于filtered,filtered小于100表示可以通过添加索引来优化,即直接的时间比较可以通过索引来优化。

添加索引

我们给字段添加索引。

2024-03-20-13-06-26-20240320130625

然后再次使用上述两条语句查询:

直接进行时间比较,执行时间分别为:0.335s,0.301s,0.299s

使用TO_DAYS比较,执行时间分别为:1.897s,1.919s,1.893s

可以发现,在添加索引的情况下,直接比较时间更快!

结论

在对应时间字段不添加索引的情况下,TO_DAYS函数比直接比较时间更快!

但是在使用索引的情况下,直接比较时间更快!