
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`;
它因索引(device,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行为是什么原因,我该如何解决?
但是,在拥有battled this on their issue tracker之后,最好的猜测是它是由this fix added in 5.7.3引起的回归:
Partitioning: Index condition pushdown did not work with partitioned tables. (Bug #17306882, Bug #70001)
我们能够通过在my.cnf中设置此问题来规避问题,从而强调了这一理论:
optimizer_switch = index_condition_pushdown =关
通过使用SET [GLOBAL] optimizer_switch =’index_condition_pushdown = off’,可以在不重新启动的情况下尝试此操作.
我们还查看了ORDER BY -`utc` ASC方法,但因为它将filesort添加到每个执行计划中而被吓跑了.
转载注明原文:MySQL 5.7奇怪的性能降低与ASC / DESC在分区表上的顺序 - 乐贴网