Mysql分区:包括日期范围之外的分区

时间:2010-03-19 10:01:52

标签: mysql database-partitioning

我刚刚尝试根据日期配置分区,但似乎mysql仍然包含一个没有相关数据的分区。它将使用相关的 分区但也包括最老的由于某种原因。我做错了吗?

版本为5.1.44(MyISAM)

我首先根据“day”添加了几个分区,其类型为“date”

ALTER TABLE ptest
PARTITION BY RANGE(TO_DAYS(day))
(
PARTITION p1 VALUES LESS THAN (TO_DAYS('2009-08-01')),
PARTITION p2 VALUES LESS THAN (TO_DAYS('2009-11-01')),
PARTITION p3 VALUES LESS THAN (TO_DAYS('2010-02-01')),
PARTITION p4 VALUES LESS THAN (TO_DAYS('2010-05-01'))
);

查询后,我发现它使用的“旧”分区不应包含任何相关数据。

mysql> explain partitions select * from ptest where day between '2010-03-11' and '2010-03-12';
+----+-------------+------------+------------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table      | partitions | type  | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+------------+------------+-------+---------------+------+---------+------+------+-------------+
| 1  | SIMPLE      | ptest      | p1,p4      | range | day           | day  | 3       | NULL | 79   | Using where |
+----+-------------+------------+------------+-------+---------------+------+---------+------+------+-------------+

当我选择一天时,它按预期工作:

mysql> explain partitions select * from ptest where day = '2010-03-11';
+----+-------------+------------+------------+------+---------------+------+---------+-------+------+-------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref   | rows | Extra |
+----+-------------+------------+------------+------+---------------+------+---------+-------+------+-------+
| 1  | SIMPLE      | ptest      | p4         | ref  | day           | day  | 3       | const | 39   |       |
+----+-------------+------------+------------+------+---------------+------+---------+-------+------+-------+

2 个答案:

答案 0 :(得分:2)

这实际上是预期的结果,因为最旧的分区将始终保存未评估为有效日期的值(null)。解决此问题的方法是创建一个额外的分区,该分区不包含任何数据,并且在最早的日期之前存在于所有值中。此分区将始终被扫描,但由于它是空的,因此对性能几乎没有影响。

http://bugs.mysql.com/bug.php?id=49754

答案 1 :(得分:1)

您已经在TO_DAYS(日期)进行了分区,这意味着除非您对约束条件应用TO_DAYS(日期),否则分区修剪主要仅在简单情况下进行。

你必须这样做,例如select * from ptest TO_DAYS('2010-03-11')和TO_DAYS('2010-03-12')之间的日期 - 尽管在这种情况下可能是mysql之间的缺点。

在mysql中对日期进行分区很难,并且在分区实现中存在很多缺点,至少如果你想要涵盖很多不同的查询约束,我们通常会在指向日历的表中放置一个整数id而不是一个DATE类型,因为我们发现mysql处理一个简单整数上的分区比相对于涉及函数的列上的分区(例如TO_DAYS)更可靠

create table datatbl (
  time_id int NOT NULL,
  ....
);

time_id引用预先填写了未来10年日期的日历,如

create table calendar (
  time_id int primary key
  year int NOT NULL,
  month int NOT NULL,
  day int NOT NULL,
  dayofyear int NOT NULL,
  quarter int NOT NULL,
  is_weekend char(1) NOT NULL,
  db_date DATE not NULL,
  unique index(year,month,day),
  unique index(dbdate)
);

查询已加入此表,因此抓取一个月的所有数据只需where cal.year = 2010 and cal.month = 1。或者它可以cal.db_date between '2010-01-01' and '2010-01-31'

完成

datatbl在time_id上​​进行了分区,上述查询将使mysql进行分区修剪。 time_id也是年/月/日的复合,因此2010-03-03的time_id将是整数20100303,不应该用于查询,它只是方便自动创建新/删除的脚本旧分区。