如果LEFT JOIN
像DATE_FORMAT
功能或任何其他功能會產生正確的結果,但它可能是方式比它慢可能是結果。如果@amdixon的答案中顯示的簡單方法的性能是合適的,那麼就使用它。
但是,有幾件事情可以做得更快。一旦您的表增長到30M行(30天,每天1M行),您可能需要考慮它們。
毫無疑問,表date_hour
必須在hour
列上具有索引(實際上是主鍵)。這將有助於當你使用這樣的搜索條件來快速查找特定日子的幾行:
WHERE
date_hour.hour >= '2015-05-01 00:00:00'
AND date_hour.hour < '2015-05-02 00:00:00'
要記住的另一個重要的事情 - 如果你有一個給定的一天1M行,你需要計算計數那一天,服務器必須至少讀取這些1M行。你無法避免這種情況。讀取1M行不會很快,但如果整個表是30M行,那麼讀取1M行比顯示整個表明顯更好。
因此,服務器應該能夠有效地查找特定日子的行(讀 - 應該有一個索引)。 任何查詢在加入時將從log_date
列中刪除分鐘和秒數,但無法使用索引,因此服務器必須掃描整個表my_data
。
選項1
上my_data
添加的索引。 log_date
。將明確的過濾器添加到WHERE
子句。它不會改變結果,但希望能給服務器提供一個很好的提示來使用my_data
上的索引。 log_date
查找必要的行並避免完整掃描。如果你使用DATE_FORMAT
將datetime
轉換爲字符串,並且它不會將date_hour.hour
轉換爲字符串以進行比較(從而否定date_hour.hour
上存在索引),那麼MySQL可能足夠智能。也許不會。我更喜歡以下方法從datetime
中刪除分鐘和秒,而不將其轉換爲字符串。
TIMESTAMPADD(HOUR,
TIMESTAMPDIFF(HOUR,'2015-01-01 00:00:00',DateTimeValue),
'2015-01-01 00:00:00')
只要沒有分鐘和秒,我們可以使用任何常數而不是'2015-01-01'。可以使用相同的方法將datetime
截斷爲任何其他邊界 - 分,日,周,月,年。
SELECT
date_hour.hour,
COUNT(my_data.log_date) AS count
FROM
date_hour
LEFT JOIN my_data ON
date_hour.hour = TIMESTAMPADD(HOUR, TIMESTAMPDIFF(HOUR,'2015-01-01 00:00:00',my_data.log_date), '2015-01-01 00:00:00')
WHERE
date_hour.hour >= '2015-05-01 00:00:00' AND
date_hour.hour < '2015-05-02 00:00:00' AND
my_data.log_date >= '2015-05-01 00:00:00' AND
my_data.log_date < '2015-05-02 00:00:00'
GROUP BY
date_hour.hour
ORDER BY
date_hour.hour
;
即使服務器將使用上date_hour
和my_data
索引找到所需的行,它仍然有權加入基於函數的結果,並用1M行可能很難。最有可能的是,它必須將該函數的1M結果存儲到臨時表中,對其進行排序然後加入。這些種類通常很昂貴,特別是如果它們不在內存中(1M行很可能在磁盤上完成)。
選項2
爲了優化該進一步和避免在運行中,我會考慮增加一個持久柱log_hour
到my_data
表,這將連同主柱log_date
填充和將所述datetime
的操縱包含log_date
值,無分鐘和秒。您可以將其視爲預先計算或緩存。一旦你在這個列上有索引log_hour
服務器應該能夠有效地找到並加入找到的行。查詢變得微不足道,它不使用log_date
列的話,那只有log_hour
用途:
SELECT
date_hour.hour,
COUNT(my_data.log_hour) AS count
FROM
date_hour
LEFT JOIN my_data ON date_hour.hour = my_data.log_hour
WHERE
date_hour.hour >= '2015-05-01 00:00:00' AND
date_hour.hour < '2015-05-02 00:00:00' AND
my_data.log_hour >= '2015-05-01 00:00:00' AND
my_data.log_hour < '2015-05-02 00:00:00'
GROUP BY
date_hour.hour
ORDER BY
date_hour.hour
;
可以留在加入'DATE_FORMAT(my_data.log_date,「%Y-%間%d%H:00 :00「)' – amdixon
...並保留在開始表中只有24個recorss –
您的SQL顯示正確。在dh.hour和md.log_date上創建索引並使用'where dh.hour> ='2015-05-01 00:00:00'和dh.hour <'2015-05-02 00:00:00''作爲表示日期/時間的一致性。 – zedfoxus