麻烦获取分区来改变查询时间

时间:2019-05-03 18:10:09

标签: mysql database partitioning

我只是对带有一些虚拟数据的分区进行了一些试验,到目前为止,优化我的查询还没有运气。

我从Internet上下载了一个数据集,该数据集由一个measurements表组成:

CREATE TABLE `partitioned_measures` (
  `measure_timestamp` datetime NOT NULL,
  `station_name` varchar(255) DEFAULT NULL,
  `wind_mtsperhour` int(11) NOT NULL,
  `windgust_mtsperhour` int(11) NOT NULL,
  `windangle` int(3) NOT NULL,
  `rain_mm` decimal(5,2) DEFAULT NULL,
  `temperature_dht11` int(5) DEFAULT NULL,
  `humidity_dht11` int(5) DEFAULT NULL,
  `barometric_pressure` decimal(10,2) NOT NULL,
  `barometric_temperature` decimal(10,0) NOT NULL,
  `lux` decimal(7,2) DEFAULT NULL,
  `is_plugged` tinyint(1) DEFAULT NULL,
  `battery_level` int(3) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
/*!50100 PARTITION BY RANGE (TO_DAYS(measure_timestamp))
(PARTITION `slow` VALUES LESS THAN (736634) ENGINE = InnoDB,
 PARTITION `fast` VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */

只是一个学习练习我想尝试用measure_timestamp对度量进行划分(在没有索引帮助的情况下)。具体来说,我认为尝试将最近一个月单独放在一个分区中会很有趣。 (我知道最好有相同大小的分区,但我只是想尝试一下)

我使用以下命令添加了分区(请注意,数据集于2016年12月结束,并且绝大多数数据点位于前几个月):

ALTER TABLE partitioned_measures 
    PARTITION BY RANGE(TO_DAYS(measure_timestamp)) (
        PARTITION slow VALUES LESS THAN(TO_DAYS('2016-12-01')), 
        PARTITION fast VALUES LESS THAN (MAXVALUE)
    );

要进行查询,我正在查看第二个及以后的所有条目(以确保只在最新的分区中查找):

select SQL_NO_CACHE COUNT(*) FROM partitioned_measures 
    WHERE measure_timestamp >= '2016-12-02' 
    AND DAYOFWEEK(measure_timestamp) = 1;

当我在其前面添加一个EXPLAIN时,会得到以下信息:

+----+-------------+----------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table                | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+----------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | partitioned_measures | slow,fast  | ALL  | NULL          | NULL | NULL    | NULL | 1835458 |    33.33 | Using where |
+----+-------------+----------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+

但是查询时间大约与分区之前相同(〜1.6秒)。我以前从未使用过分区,所以我觉得我缺少一些概念上的东西。

2 个答案:

答案 0 :(得分:1)

棘手,但我找到了一个可行的解决方案,或者我应该说一种解决方法,它似乎是MySQL错误?

   ALTER TABLE partitioned_measures 
    PARTITION BY RANGE COLUMNS(measure_timestamp) (
        PARTITION slow VALUES LESS THAN('2016-12-01'), 
        PARTITION fast VALUES LESS THAN(MAXVALUE)
    );

请参见demo,该指南确实正确使用了分区修剪

我注意到语法here

使用

时,如果分割分区不正确,我仍然会发现它
    ALTER TABLE partitioned_measures 
    PARTITION BY RANGE(TO_DAYS(measure_timestamp)) (
        PARTITION slow VALUES LESS THAN(TO_DAYS('2016-12-01')), 
        PARTITION fast VALUES LESS THAN (MAXVALUE)
    );

MySQL 5.7应该能够执行TO_DAYS()很好的分区修剪

  

修剪还可以应用于在DATE或   分区表达式使用YEAR()或DATETIME列时   TO_DAYS()函数。此外,在MySQL 5.7中

source

请参阅demo,它没有正确使用分区修剪,我已经尝试alot使其工作,但我认为所有方法都失败了。

答案 1 :(得分:1)

说明:

did 进行了您要求的修剪,但是它添加了 first 分区。为什么?因为在那里放了不好的约会。

解决方法是使用伪造的 first 分区:

/*!50100 PARTITION BY RANGE (TO_DAYS(measure_timestamp))
({ARTITION bogus  VALUES LESS THAN (0)      ENGINE = InnoDB,   -- any small value
 PARTITION `slow` VALUES LESS THAN (736634) ENGINE = InnoDB,
 PARTITION `fast` VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */

参考文献被埋在https://dev.mysql.com/doc/refman/5.7/en/partitioning-handling-nulls.html

如果您拥有的分区数量不多,那么您可能会更清楚地看到它选择了所需的分区,并且总是第一个分区。

使用罕见的exceptions,分区无法提供比从具有合适索引的未分区表获得的更好的性能。在这种情况下,INDEX(measure_timestamp)。 (或带有INDEX(dow, measure_timestamp)的虚拟列。)