2012-08-28 70 views
3

我有一個表:MySQL查詢不使用索引

CREATE TABLE `p` ( 
`id` bigint(20) unsigned NOT NULL, 
`rtime` datetime NOT NULL, 
`d` int(10) NOT NULL, 
`n` int(10) NOT NULL, 
PRIMARY KEY (`rtime`,`id`,`d`) USING BTREE 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

和我有一個查詢:

select id, d, sum(n) from p where rtime between '2012-08-25' and date(now()) group by id, d; 

我運行在一個小本上查詢說明表(2條),它告訴我它會用我的PK:

id | select_type | table | type | possible_keys key | key  | key_len | ref | rows | Extra 
1 | SIMPLE  | p  | range | PRIMARY   | PRIMARY | 8  | NULL | 1 | Using where; Using temporary; Using filesort 

但是當我使用相同的查詢在同一個表 - 只是這一次它是巨大的(350萬條記錄) - 它寧願去通過所有的記錄,而忽略了我的鑰匙

id | select_type | table | type | possible_keys | key | key_len | ref | rows  | Extra 
1 | SIMPLE  | p  | ALL | PRIMARY  | NULL | NULL | NULL | 355465280 | Using where; Using temporary; Using filesort 

顯然,這是極其緩慢.. 誰能幫助?

編輯:這個簡單的查詢也正在時間的顯著量:

select count(*) from propagation_delay where rtime > '2012-08-28'; 
+0

你可能想要考慮在http://dba.stackexchange.com上詢問這個問題,看起來他們可能會更好地配置來解釋這種行爲 - ofcourse我並沒有敲那個人的l33t SQL skillz :) – jammypeach

+0

你修了桌子嗎? http://dev.mysql.com/doc/refman/5.1/en/repair-table.html – jcho360

回答

1

您的疑問:

...WHERE rtime between '2012-08-25' and date(now()) group by id, d; 

採用RTIME,並通過ID和d組。至少你應該索引rtime。您可能還想按此順序嘗試索引rtime, id, d, n,但是當您這樣做時,您會發現索引將包含或多或少與表格相同的數據。

也許,優化程序會做一些計算,並得出結論:使用索引並不值得。

我只在rtime上留下索引。真正重要的是有多少記錄匹配WHERE - 如果它們只有幾個,可以方便地讀取索引並在表格中跳來跳去。如果它們是幾個,也許最好順序掃描整個表格,節省往返讀數。

查詢是得到一個大塊掉那些350萬的 - 我說幾個百萬

好吧,那麼它很有可能是快速提取半打萬條記錄的累計成本從索引中,然後從主表往返穿梭,以恢復這六十萬條記錄,超過打開主表的成本,並在整個過程中通過所有350M記錄進行分組和總結。

在這種情況下,如果你總是(或大部分)上rtime運行彙總查詢,該表是一個累積(歷史)表,每對夫婦(id, d)每天看到的條目數的分數,你可以考慮創建按日期聚合輔助表。即在(比方說)午夜,運行查詢和

INSERT INTO aggregate_table 
    SELECT DATE(@yesterday) AS rtime, id, d, sum(n) AS n 
    FROM main_table WHERE DATE(rtime) = @yesterday GROUP BY id, d; 

aggregate_table的數據只有每每對夫婦(id, d)持有n這一天的總和一個條目;該表比例較小,查詢速度更快。這假定你有一個相對較少的數字(id, d),並且他們每個人每天在主表中生成大量的行。如果一對夫婦每分鐘記錄一次記錄,那麼聚合速度應該加快三個數量級以上(相反,如果每天有兩次使用大量不同的傳感器,則收益可以忽略不計)。

+0

我試過失去'group by'(旨在將它分組到代碼中),但它仍然沒有使用它。 至於你的問題 - 查詢是從這3.5億美元中得到一大塊 - 我會說幾百萬。 – phistakis

+0

我會添加到答案... – LSerni

1

在你的第二個查詢中,日期範圍會返回很多行,MySQL決定不使用索引。它這樣做是因爲n未包含在索引中。一個非覆蓋索引仍然是一個查找,並且執行大量的查找比掃描錶慢。

爲了使用索引,您需要減少選定行的數量,或者在索引中包含n以具有完整的「覆蓋」索引。