非常相似的MySQL查询结果会大大改变查询持续时间(时间跨度为WHERE)

时间:2018-10-08 10:58:27

标签: mysql performance

我有一个MySQL表,其中约有60万行(Engine:InnoDB)。 MySQL在运行Ubuntu 16.04 LTS的虚拟机中运行。如果相关,MySQL服务器版本为5.7.23。

WHERE子句中的列(open_timeclose_time)均已建立索引,并且均为DATETIME列。

我将(体积)的总和作为一栏。

此查询立即返回(0.000秒):

SELECT *
FROM klines
WHERE (open_time between '2018-01-01 00:00:00' AND '2018-01-01 12:00:00')
;

EXPLAIN输出: enter image description here

这一次要花几乎一秒钟的时间(在10次尝试之间在0.640到0.703秒之间变化):

SELECT SUM(volume)
FROM klines
WHERE open_time >= '2018-01-01 00:00:00' AND close_time <= '2018-01-01 12:00:00'
;

EXPLAIN输出: enter image description here

请注意,两个查询都返回大约相同的行(第一行返回720,第二行返回721。第二个查询返回相同的720行,第一个返回,另加另一个)。

因此,如果我只想获取行,那么我将WHERE子句用于两列还是一列都没有关系。但是,如果我想获取列的总和,当我对两列使用WHERE子句时,查询的速度将大大降低。但是,如果我只使用一列,它会立即再次返回。

虽然我完全可以使用在两个open_time条件之间查询表的查询,但是我真的很好奇发生了什么。

那么,这背后的原因是什么?

1 个答案:

答案 0 :(得分:1)

open_time between '2018-01-01 00:00:00'
              AND '2018-01-01 12:00:00'

可以轻松地使用INDEX(open_time)仅触摸有趣的行。但这不可能使索引突然停止:

     open_time >= '2018-01-01 00:00:00'
AND close_time <= '2018-01-01 12:00:00'

INDEX(open_time)可以使用,但是将扫描表的后半部分。类似地,INDEX(close_time)将扫描表的前半部分。现在有两种方法都可以。

可能还有一个其他地方都看不到的约束:

  • [open..close]时间范围不重叠?
  • 打开总是<关闭吗?

这些不能在标准SQL中指定,也没有任何索引公式可以利用这两个约束。

这里有两行会弄乱任何优化尝试:

INSERT INTO klines (open_time,             close_time)
            VALUES ('2018-01-01 06:00:00', '2037-12-31'),
                   ('1971-01-01',          '2018-01-01 06:00:00')
                   ('2037-01-01',          '1971-01-01')

有一些修复程序,但是它们要求要么假设不重叠,要么处理查询是很严格的方法;或玩水桶。