【问题标题】:MySQL 5.7 strange perfomance reduction with order by ASC/DESC on partitioned tableMySQL 5.7 奇怪的性能降低与分区表上的 ASC/DESC 顺序
【发布时间】:2016-12-25 16:57:08
【问题描述】:

在将 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 服务器下,两个查询都很快(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出现这种奇怪行为的原因是什么,我该如何解决?

【问题讨论】:

  • 你能用解释检查一下慢查询和快查询使用的索引吗?
  • 不出意外,两者都使用 idx_devutc。更重要的是,使用 'FORCE INDEX (idx_devutc)' 修饰符的相同查询显示相同的结果。
  • 额外部分没有文件排序?
  • 在从 5.6 更新到 5.7.16 并引入分区后,我们看到了同样的问题。 “解释”显示相同的计划,但将 ASC 更改为 DESC 会导致响应变慢几个数量级。
  • 我仍然不知道问题的原因和正确的解决方案。但是您可以使用一些技巧来避免性能泄漏。而不是“ORDER BY ID DESC”使用“ORDER BY -ID”

标签: mysql database


【解决方案1】:

我不是 MySQL 开发人员,所以我不知道全部细节。

不过,有了battled this on their issue tracker之后,最好的猜测是this fix added in 5.7.3引起的回归:

分区:索引条件下推不适用于分区表。 (错误 #17306882,错误 #70001)

我们能够通过在my.cnf 中设置它来规避这个问题,这一事实强调了这一理论:

optimizer_switch=index_condition_pushdown=off

可以使用SET [GLOBAL] optimizer_switch='index_condition_pushdown=off' 尝试此操作而无需重新启动。

我们还研究了 ORDER BY -`utc` ASC 方法,但被吓跑了,因为它将 Using filesort 添加到每个执行计划中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-25
    • 2016-05-09
    • 2021-09-21
    • 1970-01-01
    • 2017-10-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多