具有范围选择的Mysql范围分区

时间:2016-11-03 17:45:55

标签: mysql partitioning

我找不到像我这样的例子,所以这就是事情:

我有一个需要聚合的大数据集。

我们谈论的是〜%500M行,日期字段从2y之前到现在不等。 我的第一直觉是通过这个字段对表进行分区(在日期字段上创建一个分区),每个分区大约留下20M行。

然后我在其他字段上有索引,我将聚合/分组。

这是我的表定义(为简洁起见而简化):

create table t1(
date_field datetime not null,
additional_id int not null,
category_id int not null,
value_field1 double,
value_field2 double,
primary key(additional_id,date_field)
)
ENGINE=InnoDB 
PARTITION BY RANGE(YEAR(date_field)*100 + MONTH(date_field)) (
PARTITION p_201411  VALUES LESS THAN (201411),
PARTITION p_201412  VALUES LESS THAN (201412),

#all the partitions until the current month...

PARTITION p_201610  VALUES LESS THAN (201610),
PARTITION p_201611  VALUES LESS THAN (201610),
PARTITION p_catchall VALUES LESS THAN MAXVALUE );

如果我执行直接获取日期的查询,则根据查询顶部的解释分区的输出,仅使用该月的分区:

select value_field1 where additional_id=x and date_field='2014-11-05'

但是,如果我使用日期范围(即使在同一分区内),则扫描所有分区

select value_field1 where additional_id=x and date_field> '2014-11-05' and date_field <'2014-11-10'

(如果我在两者之间使用,结果相同)。

我在这里缺少什么?这真的是分区这个表的正确方法吗?

提前致谢

1 个答案:

答案 0 :(得分:0)

简答:不要对PARTITION BY RANGE使用复杂的表达式。

答案很长:(除了批评BY RANGE对范围查询的实施。)

相反,这样做:

PARTITION BY RANGE (TO_DAYS(date_field)) (
PARTITION p_201411  VALUES LESS THAN (TO_DAYS('2014-11-01')),
...
PARTITION p_catchall VALUES LESS THAN MAXVALUE );  -- unchanged

较新版本的MySQL可以使用更友好的表达式。

如果这是您的典型查询:

additional_id=x and date_field> '2014-11-05'
                and date_field <'2014-11-10'

然后分区不比同等的非分区表快。您甚至可以获得非分区版本的完美索引。

另一方面,如果DROPping旧版分区到期时为PARTITIONing,则additional_id int非常出色。

25个分区是好的。

More discussion

附注:INT UNSIGNED限制为20亿,所以你是溢出的1/4。 ALTER会让你达到40亿;你可能会考虑additional_id。 (当然,我不知道compile 'org.apache.poi:poi-ooxml:3.15' 在此表中是否是唯一的;所以也许这不是问题。)