2014-03-12 54 views
1

我有一張表,每天至少有兩百萬條記錄,每天我必須運行統計信息。由於我的統計查詢可能需要三個小時才能運行:我試圖優化表格。我想我會利用分區,以便查詢優化器可以利用分區修剪,但是當我運行我的查詢時,所有分區仍在被查看。使用分區修剪的查詢優化

我創建了一個測試表,還對MySQL的小提琴現已

CREATE TABLE `log_tests` (
    `_id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    `name` varchar(25) DEFAULT NULL, 
    PRIMARY KEY (`_id`,`timestamp`), 
    KEY `log_tests__timestamp` (`timestamp`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 
/*!50100 PARTITION BY RANGE (unix_timestamp(`timestamp`)) 
(PARTITION p201401 VALUES LESS THAN (unix_timestamp('2014-02-01 00:00:00')) ENGINE = MyISAM, 
PARTITION pNew VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ 
; 

INSERT INTO `log_tests` (`timestamp`, `name`) VALUES ('2014-01-10 01:01:01', '1'); 
INSERT INTO `log_tests` (`timestamp`, `name`) VALUES ('2014-01-11 01:01:01', '2'); 
INSERT INTO `log_tests` (`name`) VALUES ('3'); 
INSERT INTO `log_tests` (`name`) VALUES ('4'); 
INSERT INTO `log_tests` (`name`) VALUES ('5'); 

...當我運行了1月30日之前時間軸中的其中一個SELECT語句,這兩個分區看,而不是隻是p201401分區。例如執行以下:

explain partitions select * from log_tests 
where unix_timestamp(`timestamp`) < unix_timestamp('2014-01-31 00:00:00') 

回報:

id | select_type | table  | partitions | type | possible_keys | key | key_len | ref | rows | Extra 
--------------------------------------------------------------------------------------------------------------- 
1 | SIMPLE  | log_tests | p201401,pNew | ALL | NULL   | NULL | NULL | NULL | 5 | Using where 

智慧任意關鍵詞???

回答

3

問題在於你如何做查詢,分區工作。

當你

explain partitions select * from log_tests 
where unix_timestamp(`timestamp`) < unix_timestamp('2014-01-31 00:00:00') 

你申請一個函數列值。總是在向列應用函數時,MySQL必須執行全表掃描,因爲所有行都需要應用該函數才能評估表達式。如果您想到功能rand(),那麼理解它可能會更容易,那麼顯然每行都必須進行評估。

如果你改變你的查詢

explain partitions select * from log_tests 
where timestamp < '2014-01-31 00:00:00'; 

它正確地使用只有一個分區。看到這個fiddle

順便說一下,這適用於所有查詢,而不僅限於分區表上的查詢。您不應該將函數應用於列值,每次都會執行全表掃描。

+1

+1這是MySQL用戶試圖優化查詢最常見的絆腳石之一。 FWIW,在表達式上創建索引一直是[2004年以來的一項功能請求](http://bugs.mysql.com/bug.php?id=4990)。 –

+0

呃,好吧,那有點愚蠢:(我確定我必須在分區所基於的'timestamp'列上做一個unix_timestamp。謝謝你澄清這一點。 – Kate