将MySQL服务器更新到5.7版(在Ubuntu 16.04 LTS下)时,我遇到了一些奇怪的麻烦。
Preambula :我有一些包含大量记录的表(约2.5亿)。简而言之,这个表具有这样的结构:
CREATE TABLE `device_data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`device` int(11) DEFAULT NULL,
`data` double NOT NULL DEFAULT '0',
`utc` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`utc`,`id`),
KEY `id` (`id`),
KEY `idx_devutc` (`device`,`utc`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
/*!50100 PARTITION BY RANGE (`utc`)
(PARTITION y_min VALUES LESS THAN (1200000000) ENGINE = MyISAM,
PARTITION y_121 VALUES LESS THAN (1210000000) ENGINE = MyISAM,
PARTITION y_122 VALUES LESS THAN (1220000000) ENGINE = MyISAM,
...
...
...
PARTITION y_167 VALUES LESS THAN (1670000000) ENGINE = MyISAM,
PARTITION y_168 VALUES LESS THAN (1680000000) ENGINE = MyISAM,
PARTITION y_169 VALUES LESS THAN (1690000000) ENGINE = MyISAM,
PARTITION y_max VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */
那么,为什么它有这种不寻常的主键(UTC,ID)?字段ID是自动增量,它可以是主键。好吧,我们需要按字段UTC对表进行分区,并且MySQL说要这样做,字段UTC必须是主键或至少是主键的第一部分。我们不能使用UTC作为主键,因为设备每秒可以发送几次数据,所以我们必须使用这样一个奇怪的主键:(UTC,ID)。这没关系。
我们还有(device,utc)对此表进行索引和索引。为什么?因为我们需要执行某些设备在特定时间段内检索数据的查询,例如:
SELECT `utc`, `data`
FROM `device_data`
WHERE `device` = :DeviceId AND `utc` >= :UtcFrom AND `utc` < :UtcTo
ORDER BY `utc`;
由于索引(设备,utc),它非常快。
Ambula :将MySQL服务器升级到版本5.7(从5.0或5.1,我现在不确定)后,一些查询变得非常慢(2-3分钟而不是100-200毫秒) )。一些小调查发现了一个条件:当排序顺序是后代时,查询速度会下降。
此查询仍然很快(100毫秒):
SELECT `utc`, `data`
FROM `device_data`
WHERE `device` = :DeviceId AND `utc` >= :UtcFrom AND `utc` < :UtcTo
ORDER BY `utc` ASC;
但是这个查询非常慢(~180秒):
SELECT `utc`, `data`
FROM `device_data`
WHERE `device` = :DeviceId AND `utc` >= :UtcFrom AND `utc` < :UtcTo
ORDER BY `utc` DESC;
当然,使用相同的参数值。 在以前版本的MySQL Server中,两个查询都很快(100-200毫秒)。
经过两天的努力工作后,我发现了一些避免这个问题的技巧:
SELECT `utc`, `data`
FROM `device_data`
WHERE `device` = :DeviceId AND `utc` >= :UtcFrom AND `utc` < :UtcTo
ORDER BY -`utc` ASC;
(在ORDER BY中的utc
之前的减号上加上
此查询也很快,以毫秒结束,并按照相反的顺序返回记录,正如我们所需。
问题:这种奇怪的MySQL行为是什么原因,我该如何解决?
答案 0 :(得分:4)
我不是MySQL开发者,所以我不知道详细信息。
然而,在battled this on their issue tracker之后,最好的猜测是它是由this fix added in 5.7.3引起的回归:
分区:索引条件下推功能不适用于分区表。 (Bug#17306882,Bug#70001)
我们能够通过在my.cnf
中设置此问题来规避问题,从而强调了这一理论:
optimizer_switch=index_condition_pushdown=off
可以尝试使用SET [GLOBAL] optimizer_switch='index_condition_pushdown=off'
而无需重新启动。
我们还查看了ORDER BY -`utc` ASC
方法,但在为每个执行计划添加Using filesort
时被吓跑了。