2012-04-26 51 views
0

更新:它似乎是問題(如各種人所述)正在將日期時間字段更改爲查詢中的日期字段。mysql:RIGHT JOIN查詢涉及日曆表的速度問題

使用DATE(all_griefs_tbl.actioned_date太慢了,是否有一種更快的方法,但不會將actioned_date更改爲日期字段或將其拆分爲日期和時間字段?

我有2個表,一個用的是有一個狀態和日期時間字段和記錄負載另一種是從2008年日期2015年

日曆表我想離開是每一個日期在一個時間段和已經被「接受」每一天的記錄數 - 即使計數爲零 - 這應該是這樣的:

| Date  | number_accepted | 
---------------------------- 
2012-03-01  723 
2012-03-02  723 
2012-03-03  1055 
2012-03-04  1069 
2012-03-05  0 
2012-03-06  615 
2012-03-07  0 
2012-03-08  1072 
2012-03-09  664 
2012-03-10  859 
2012-03-11  0 
2012-03-12  778 
2012-03-13  987 

我試過以下,但也僅僅是快足夠少量的數據樣本(-1000行)。我需要的東西是非常適用於至少600K行

SELECT calendar.datefield AS Date, 
     COUNT(all_griefs_tbl.actioned_status) AS total_griefs 
FROM all_griefs_tbl 
RIGHT JOIN calendar 
    ON (DATE(all_griefs_tbl.actioned_date) = calendar.datefield) 
    AND all_griefs_tbl.actioned_status = 'accepted' 
WHERE calendar.datefield < CURDATE() 
GROUP BY calendar.datefield 

感謝

編輯:根據要求

id select_type  table   type possible_keys  key    key_len  ref  rows Extra 
1 SIMPLE   calendar  range PRIMARY   PRIMARY   3   NULL 1576 Using where; Using index 
1 SIMPLE   all_griefs_tbl ref  actioned_status actioned_status 153   const 294975 
+0

請提供執行計劃(在選擇之前添加解釋時的輸出) – 2012-04-26 13:38:59

+0

您的日曆表中包含每個日期。你從2008年開始每天都會去現在的日期嗎?您可能會更好地使用每天計數的彙總表,而不是每次重新計算。 – DRapp 2012-04-26 16:29:10

+0

這個想法是獲取highstocks圖表的數據 - http://www.highcharts.com/,因此從2008年到現在將是理想的。只要至少有1個,我就可以每天獲得計數......如果我無法實現這個目標,我想這將會回落。 – eek 2012-04-26 17:01:12

回答

1

的一點想法...

首先,儘管執行計劃你聲明你想在db查詢中返回沒有任何值的日子,我實際上會對結果集進行檢查,無論它在哪裏處理。無論何時進行連接,都會使查詢變得更加複雜,並需要更多內存來處理它們。在這種情況下,我不會認爲您使用日曆表作爲關係數據庫的特別有效的用途。

編輯:澄清,如何調用查詢?即是否有一些程序(您正在開發)訪問數據庫,運行查詢並顯示結果?如果是這樣,我建議讓這個程序在演示前處理結果。其次,如果你承諾'加入',你真的應該在all_griefs_tbl.actioned_date上有一個索引,因爲這是你進行連接的列。或者,您可以在calendar.datefield上指定外鍵。

三,您是否需要使用功能DATE(all_griefs_tbl.actioned_date)?這不是已經約會嗎? (不知道你的數據類型,但如果這和calendar.datefield不是相同的數據類型,這看起來像不好的數據庫設計。)

編輯:根據你所說的,你可能想分裂成all_griefs_tbl.actioned_date兩列日期列all_griefs_tbl.actioned_date和時間戳列all_griefs_tbl.actioned_time。目前,您在all_griefs_tbl的每一行上都運行這個DATE()函數,以便進行連接 - 這將很快導致查詢緩慢。這也可以讓你在日期時間列上添加一個索引,這也會提高連接的性能(鑑於你當前的數據庫設計,我並不感到驚訝actioned_date索引沒有幫助 - 我寧可期待,因爲DATE()函數,如果您重新運行EXPLAINactioned_date列的索引,因爲它目前代表,它不會顯示它使用此索引all_griefs_tbl。)

第四,您可能要考慮在all_griefs_tbl.actioned_status中存儲了哪些類型的信息。可以用布爾值替換嗎?這在存儲和處理數據時會更有效率。 (雖然這又取決於你的數據庫設計。)

編輯:你可以考慮改變all_griefs_tbl.action_status到一個更小的數據類型 - 我期望它目前是一個varchar,但你可以很容易地改變這個單一(或小)char數據類型,甚至是一些布爾人。但是,我不認爲這會成爲主要的性能開銷,而且根據項目的需要,它確實是一個更爲複雜的數據庫設計決策。

+0

感謝您的回覆。我使用的是日曆表,所以我可以在一段時間內得到所有日期,以免丟失。如果有更好的方法,我很樂意聽到它。我沒有承諾加入,我只是不知道另一種方式去做。我確實在all_griefs_tbl.actioned_date上有了一個索引,但它似乎沒有太大區別。 calendar.datefield是日期字段,all_griefs_tbl.actioned_date是日期時間字段。這是唯一的區別。有幾種不同的狀態,all_griefs_tbl.actioned_status可能是:接受,排隊,鎖定 – eek 2012-04-26 15:10:08

+0

我想實現這裏完成的工作:http://www.richnetapps.com/using-mysql-generate-daily-sales-報告填補的差距/不同之處在於我在計算時間範圍內的行數而不是總結數值。 – eek 2012-04-26 15:24:16

+0

@eek - 我在評論中添加了評論。 – amaidment 2012-04-26 15:36:24

1

我建議從日期時間分割你的actioned_date成2個獨立的日期和時間列,可以說actioned_dateactioned_time所以你可以

ON (DATE(all_griefs_tbl.actioned_date) = calendar.datefield) 

改變你的第一個連接條件

ON (all_griefs_tbl.actioned_date = calendar.datefield) 

和添加索引

ALTER TABLE all_griefs_tbl ADD INDEX g_status_date(actioned_status, actioned_date, actioned_time); 

它可能會使您的查詢即時爲600k行的表。

+0

這是我認爲會起作用的一種解決方案,但是我想知道的是,如果有另一種方法而不是DATE(),那麼我可以使用它更快?將其拆分爲2個獨立的列將是最後的手段。 – eek 2012-04-26 17:20:32

+0

+1分拆建議 – eek 2012-04-26 17:33:37

+0

拆分將允許使用提到的索引也爲該組提供,這將有所不同,談論msecs而不是秒。 – piotrm 2012-04-26 17:39:44