mysql时间类型字段的优化技巧
最近开发一个功能时需要查询今天开播的主播用户。在业务上我们有一个数据表存储了主播每次开播的记录。表中有一个时间类型的字段表示主播开播时间。(为了业务安全,这里用time字段表明实际字段. record表示数据表)
第一种实现
在开始实现的时候想到的就是 time = 今天这种实现逻辑上比较直接。
select distinct userId
from record
where date_format(time, '%Y%m%d')=
date_format(now(), '%Y%m%d')
可以看到关键就是where
后的date_format
函数了。对日期格式进行转换。这个sql
在测试环境跑没有什么问题,在线上跑之后一直报timeout
。最后查看了慢语句汇总。发现上面的sql
也俨然在列。
第二种实现
实现思路
select distinct userId
from record
where
time >= 'YYYY-mm-dd 00:00:00'
and time <= 'YYYY-mm-dd 23:59:59'
具体实现(也可以从服务层穿参这样sql显的就不复杂了):
select distinct userId from record
where time >=
(SELECT str_to_date(DATE_FORMAT( NOW(), '%Y-%m-%d'), '%Y-%m-%d %H:%i:%s'))
and time <=(select DATE_ADD( DATE_ADD(str_to_date(DATE_FORMAT(NOW(),'%Y-%m-%d'),'%Y-%m-%d %H:%i:%s'), INTERVAL 1 DAY),INTERVAL -1 SECOND));
两种实现对比
虽然两种实现都可以完成这个功能,但是第二种在线上跑没有性能问题。此时查看sql
的执行计划explain
。
发现两个的执行计划的row
相差1000倍,并且单次测量第一种执行时间需要3000多毫秒,而第二种只需要4ms。
first row | second row |
---|---|
3000 | 3 |
first time | second time |
---|---|
3300ms | 4ms |
原因是date_format这种需要对日期进行转换,需要查询出所有行进行过滤。而第二种可以利用在time上建立索引,查询极快。