我刚刚尝试根据日期配置分区,但似乎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 | |
+----+-------------+------------+------------+------+---------------+------+---------+-------+------+-------+
答案 0 :(得分:2)
这实际上是预期的结果,因为最旧的分区将始终保存未评估为有效日期的值(null)。解决此问题的方法是创建一个额外的分区,该分区不包含任何数据,并且在最早的日期之前存在于所有值中。此分区将始终被扫描,但由于它是空的,因此对性能几乎没有影响。
答案 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,不应该用于查询,它只是方便自动创建新/删除的脚本旧分区。