我只是对带有一些虚拟数据的分区进行了一些试验,到目前为止,优化我的查询还没有运气。
我从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秒)。我以前从未使用过分区,所以我觉得我缺少一些概念上的东西。
答案 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中
答案 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)
的虚拟列。)