Mysql分区:包含超出日期范围的分区

发布于 2024-08-25 08:49:11 字数 1863 浏览 9 评论 0原文

我刚刚尝试根据日期配置分区,但似乎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'))
);

经过查询,我发现它使用“old”分区,该分区不应该包含任何相关数据。

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   |       |
+----+-------------+------------+------------+------+---------------+------+---------+-------+------+-------+

I have just tried to configure partitions based on date, but it seems that mysql still includes a partition with no relevant data. It will use the relevant
partition but also include the oldest for some reason. Am I doing it wrong?

The version is 5.1.44 (MyISAM)

I first added a few partitions based on "day", which is of type "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'))
);

After a query, I find that it uses the "old" partition, that should not contain any relevant data.

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 |
+----+-------------+------------+------------+-------+---------------+------+---------+------+------+-------------+

When I select a single day, it works as expected:

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   |       |
+----+-------------+------------+------------+------+---------------+------+---------+-------+------+-------+

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我做我的改变 2024-09-01 08:49:11

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

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

This is actually the intended result because the oldest partition will always hold values that did not evaluate to a valid date (null). A workaround for this is to create an additional partition that will hold no data and exist for all values before your oldest date. This partition will always be scanned but has little affect on performance since it is empty.

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

娇妻 2024-09-01 08:49:11

您已经在 TO_DAYS(date) 上进行了分区,这意味着分区修剪大多数情况下只会发生在简单的情况下,除非您对约束应用 TO_DAYS(date) 。

你必须这样做,例如 select * from ptest where day between 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 在 '2010-01-01' 和 '2010-01-31' 之间

datatbl 在 time_id 上进行分区,上面的查询将让mysql做分区修剪。 time_id 也是年/月/日的组合,因此 2010-03-03 的 time_id 将是整数 20100303 ,不应该用于查询,这只是自动创建 new/drop 的脚本的一个方便旧分区。

You have partitioned on TO_DAYS(date), that means partitioning pruning will mostly only occur in simple cases unless you apply TO_DAYS(date) on the constraints.

You'll have to do e.g. select * from ptest where day between TO_DAYS('2010-03-11') and TO_DAYS('2010-03-12') - although it might be in this case shortcomings in mysql between.

Partitioning on dates in mysql is hard, and there's a lot of shortcomings in the partitioning implementation, atleast if you want to cover a lot of different query constraints, we usually place an integer id in the tables pointing to a calendar instead of a DATE type, as we've found mysql to handle partitioning on a simple integer to be quite reliable compared to partitioning on columns involving a function(such as TO_DAYS) we have

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

time_id references a calendar prefilled with dates for the next 10 years looking like

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)
);

Queryies are joined to this table, so grabbing all data for a month requires just a where cal.year = 2010 and cal.month = 1 . Or it could be done as cal.db_date between '2010-01-01' and '2010-01-31'

datatbl is partitioned on time_id , and the above queries will make mysql do partitioning pruning. time_id is also a composite of year/month/date so the time_id for 2010-03-03 would be the integer 20100303 , that shouldn't be used for querying against, it is simply a convenience for the scripts that automatically create new/drop old partitions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文