2011-05-23 68 views
10

我想通過datetime列對mysql表進行分區。有一天,一個partition.The創建表的腳本是這樣的:如何通過datetime列對錶進行分區?

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; 

但是,當我選擇一些day.It無法找到partition.The 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'; 

有沒有人告訴我如何選擇某天的數據並利用partition.Thanks!

回答

7

你好你是做了錯誤的分區表的定義表定義會是這樣的:

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 

爲什麼要使用th ËTO_DAYS作爲MySQL優化將認識到分區修剪目的的兩個基於日期的功能: 1.TO_DAYS() 2.YEAR()

,這將解決您的問題..

+0

'^ 1'如果表中的年數未知,「PARTITION BY HASH(YEAR(ftime))」是否會起作用? – 2017-01-25 10:18:51

12

由HASH分區是日期時間列的一個非常糟糕的主意,因爲它不能使用partition pruning。從MySQL文檔:

修剪只能通過 HASH或KEY分區表的整數列被使用。

SELECT * FROM t4 WHERE dob >= '2001-04-14' AND dob <= '2005-10-15'; 

但是,如果在一個INT列的表存儲年份值,然後有WHERE year_col一個 查詢:例如,由於出生日期是DATE列對錶T4這個查詢無法使用修剪 > = 2001 AND year_col < = 2005可以修剪爲 。

因此,您可以將TO_DAYS(DATE())的值存儲在額外的INTEGER列中以使用修剪。

另一種選擇是使用範圍分區:

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(datetime)) (
    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'; 
+0

我正在學習分區,在'WHERE'語句中不需要使用'DATE_FORMAT()'嗎? – enchance 2015-08-10 12:14:48

+0

@Steyx - 也許你的意思是'WHERE ftime> ='2011-04-03'和ftime <'2011-04-03'+ INTERVAL 1 DAY'。 – 2015-11-26 04:31:56

0

不要使用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。這包括一段時間內滑動分區的代碼。

相關問題