如何按日期时间列对表进行分区?

tin*_*hen 15 mysql hash datetime database-partitioning

我想通过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;
Run Code Online (Sandbox Code Playgroud)

但是当我选择某天的数据时,它找不到分区.select语句是这样的:

explain partitions select * from raw_log_2011_4 where day(ftime) = 30;
Run Code Online (Sandbox Code Playgroud)

当我使用另一个语句时,它可以找到分区,但我没有选择某天的数据.

explain partitions select * from raw_log_2011_4 where ftime = '2011-03-30';
Run Code Online (Sandbox Code Playgroud)

有没有人告诉我如何选择某天的数据并利用分区.谢谢!

小智 20

HASH的分区对于datetime列来说是一个非常糟糕的主意,因为它不能使用分区修剪.来自MySQL文档:

修剪只能用于由HASH或KEY分区的表的整数列.例如,表t4上的此查询无法使用修剪,因为dob是DATE列:

SELECT * FROM t4 WHERE dob >= '2001-04-14' AND dob <= '2005-10-15';
Run Code Online (Sandbox Code Playgroud)

但是,如果表将年份值存储在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
  );
Run Code Online (Sandbox Code Playgroud)

现在,以下查询将仅使用分区p20110403:

SELECT * FROM raw_log_2011_4 WHERE ftime = '2011-04-03';
Run Code Online (Sandbox Code Playgroud)


Vin*_*982 9

嗨您正在对表定义所希望的表的定义执行错误的分区:

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;
Run Code Online (Sandbox Code Playgroud)

你的选择命令是:

explain partitions 
    select * from raw_log_2011_4 where TO_DAYS(ftime) = '2011-03-30';
Run Code Online (Sandbox Code Playgroud)

上面的命令将选择所需的所有日期,就像使用TO_DAYS命令一样

mysql> SELECT TO_DAYS(950501);
        -> 728779
mysql> SELECT TO_DAYS('2007-10-07');
        -> 733321
Run Code Online (Sandbox Code Playgroud)

为什么要使用TO_DAYS AS MySQL优化器将识别两个基于日期的函数以进行分区修剪:1.TO_DAYS()2.YEAR()

这将解决你的问题..