如何按日期时间列对表进行分区?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何按日期时间列对表进行分区?相关的知识,希望对你有一定的参考价值。
我想通过datetime列对mysql表进行分区。有一天分区。创建表脚本是这样的:
CREATE TABLE raw_log_2011_4 (
id bigint(20) NOT NULL AUTO_INCREMENT,
logid char(16) NOT NULL,
tid char(16) NOT NULL,
reporterip char(46) DEFAULT NULL,
ftime datetime DEFAULT NULL,
KEY id (id)
) ENGINE=InnoDB AUTO_INCREMENT=286802795 DEFAULT CHARSET=utf8
PARTITION BY hash (day(ftime)) partitions 31;
但是当我选择某天的数据时,它找不到分区.select语句是这样的:
explain partitions select * from raw_log_2011_4 where day(ftime) = 30;
当我使用另一个语句时,它可以找到分区,但我无法选择某一天的数据。
explain partitions select * from raw_log_2011_4 where ftime = '2011-03-30';
有没有人告诉我如何选择某天的数据并利用分区。谢谢!
HASH的分区对于datetime列是个坏主意,因为它不能使用partition pruning。来自MySQL文档:
修剪只能用于由HASH或KEY分区的表的整数列。例如,表t4上的此查询无法使用修剪,因为dob是DATE列:
SELECT * FROM t4 WHERE dob >= '2001-04-14' AND dob <= '2005-10-15';
但是,如果表将年份值存储在INT列中,则可以修剪具有WHERE year_col> = 2001 AND year_col <= 2005的查询。
因此,您可以将TO_DAYS(DATE())的值存储在额外的INTEGER列中以使用修剪。
另一种选择是使用RANGE分区:
CREATE TABLE raw_log_2011_4 (
id bigint(20) NOT NULL AUTO_INCREMENT,
logid char(16) NOT NULL,
tid char(16) NOT NULL,
reporterip char(46) DEFAULT NULL,
ftime datetime DEFAULT NULL,
KEY id (id)
) ENGINE=InnoDB AUTO_INCREMENT=286802795 DEFAULT CHARSET=utf8
PARTITION BY RANGE( TO_DAYS(ftime) ) (
PARTITION p20110401 VALUES LESS THAN (TO_DAYS('2011-04-02')),
PARTITION p20110402 VALUES LESS THAN (TO_DAYS('2011-04-03')),
PARTITION p20110403 VALUES LESS THAN (TO_DAYS('2011-04-04')),
PARTITION p20110404 VALUES LESS THAN (TO_DAYS('2011-04-05')),
...
PARTITION p20110426 VALUES LESS THAN (TO_DAYS('2011-04-27')),
PARTITION p20110427 VALUES LESS THAN (TO_DAYS('2011-04-28')),
PARTITION p20110428 VALUES LESS THAN (TO_DAYS('2011-04-29')),
PARTITION p20110429 VALUES LESS THAN (TO_DAYS('2011-04-30')),
PARTITION future VALUES LESS THAN MAXVALUE
);
现在,以下查询将仅使用分区p20110403:
SELECT * FROM raw_log_2011_4 WHERE ftime = '2011-04-03';
嗨您正在对表定义所希望的表的定义中执行错误的分区:
CREATE TABLE raw_log_2011_4 (
id bigint(20) NOT NULL AUTO_INCREMENT,
logid char(16) NOT NULL,
tid char(16) NOT NULL,
reporterip char(46) DEFAULT NULL,
ftime datetime DEFAULT NULL,
KEY id (id)
) ENGINE=InnoDB AUTO_INCREMENT=286802795 DEFAULT CHARSET=utf8
PARTITION BY hash (TO_DAYS(ftime)) partitions 31;
你的选择命令是:
explain partitions
select * from raw_log_2011_4 where TO_DAYS(ftime) = '2011-03-30';
上面的命令将选择所需的所有日期,就像使用TO_DAYS命令一样
mysql> SELECT TO_DAYS(950501);
-> 728779
mysql> SELECT TO_DAYS('2007-10-07');
-> 733321
为什么要使用TO_DAYS AS MySQL优化器将识别两个基于日期的功能以进行分区修剪:1.TO_DAYS()2.YEAR()
这将解决你的问题..
我刚刚在http://dev.mysql.com/tech-resources/articles/mysql_55_partitioning.html上阅读了一篇与此相关的MySQL博客文章。
早于5.1的版本需要特殊的体操才能根据日期进行分区。上面的链接讨论它并显示示例。
版本5.5及更高版本允许您使用非数字值(如日期和字符串)进行直接分区。
不要使用CHAR
,使用VARCHAR
。这将节省大量空间,从而减少I / O,从而加快查询速度。
reporterip
:(46)对于IP地址来说是不必要的,甚至是IPv6。有关进一步的讨论,请参阅My blog,包括如何将其缩小到16个字节。
PARTITION BY RANGE(TO_DAYS(...))
为@Steyx建议,但没有超过50个分区。尽管进行了“修剪”,但您拥有的分区越多,查询就越慢。 HASH
分区基本没用。
More discussion of partitioning, especially the type you are looking at。这包括随着时间的推移滑动分区集的代码。
以上是关于如何按日期时间列对表进行分区?的主要内容,如果未能解决你的问题,请参考以下文章