2013-04-03 127 views
0

有沒有一種方法來優化以下查詢。大約需要11秒:優化複雜GROUP BY查詢的性能

SELECT 
    concat(UNIX_TIMESTAMP(date), '000') as datetime, 
    TRUNCATE(SUM(royalty_price*conversion_to_usd* 
      (CASE WHEN sales_or_return = 'R' THEN -1 ELSE 1 END)* 
      (CASE WHEN royalty_currency = 'JPY' THEN .80 
        WHEN royalty_currency in ('AUD', 'NZD') THEN .95 ELSE 1 END)) 
    ,2) as total_in_usd 
FROM 
    sales_raw 
GROUP BY 
    date 
ORDER BY 
    date ASC 

做一個解釋,我得到:

1 SIMPLE sales_raw index NULL date 5 NULL 735855 NULL 
+0

這是一個聚合。因爲沒有WHERE子句,所以沒有什麼可做的,只是掃描整個表。在這種情況下,這是I/O性能和CPU性能問題(針對您的表達式)。你可以過濾一組(索引)日期,所以你只需要閱讀表的一部分? – 2013-04-03 19:35:14

+0

@NWest謝謝你的回覆。你能舉個例子說明你的意思是「過濾一組索引日期」嗎? – David542 2013-04-03 19:47:14

回答

2

這是一個答案,在註釋的問題。它格式更好地在這裏:

一組索引日期的過濾裝置的一個例子做這樣的事情:

where date >= AStartDateVariable 
and date < TheDayAfterAnEndDateVariable 

如果在日期字段沒有索引,創建一個。

2

您可以加快速度。您好像在date上有索引。發生的事情是,行在索引中被讀取,然後每行被查找。如果數據沒有按日期字段排序,那麼這可能不是最佳的,因爲讀取將基本上是隨機頁面。在原始表格而不是適合內存的情況下,這會導致稱爲「頁面抖動」的情況。需要記錄,頁面從內存中讀取(取代內存緩存中的另一頁),下一次讀取也可能導致緩存未命中。

要看看這是否發生,我會建議兩件事之一。 (1)嘗試刪除date上的索引或將group by條件切換爲concat(UNIX_TIMESTAMP(date), '000')。這些中的任何一個都應該將索引作爲一個因素去除。

從您的額外評論,這不是發生,雖然指數的好處似乎是在一邊。 (2)您還可以展開索引以包含查詢中使用的所有表。除了日期之外,索引還需要包含royalty_price,conversion_to_usd,sales_or_return和royalty_currency。這將允許索引完全滿足查詢,而無需在頁面中查找額外的信息。

您還可以與您的DBA一起檢查,確定您擁有足夠大的頁面緩存以匹配您的硬件功能。

+0

對於#2,你的意思是所有這些字段的複合索引?或每個獨特的索引? – David542 2013-04-03 20:01:15

+0

它看起來像#1減慢了約20%的查詢。 – David542 2013-04-03 20:02:52

+0

@GordonLinoff and upvoters:請注意,原則上索引的日期是可取的(http://dev.mysql.com/doc/refman/5.0/en/group-by-optimization.html,第一段)。 #2無法提供幫助,因爲日期的第一個索引是檢索其他字段所需的全部內容。優化程序很可能會忽略更多索引,因爲它們旨在用數據查找行,而不是數據本身。但是,也許你可以在RDMBS中說出一個情況,其中索引僅用於查找數據。 – koriander 2013-04-03 20:50:10

0

這是一個簡單的查詢組,甚至不涉及連接。我希望問題在於你正在使用的功能。

請從一個簡單的查詢開始,只是檢索日期和conversion_to_usd的總和。檢查性能並逐步建立查詢,始終檢查性能。發現肇事者不應該花很長時間。

Concats通常是緩慢的操作,但我想知道sum之後截斷可能會使優化器混淆。第二種情況可以通過加入一個貨幣代碼表和各自的百分比表來加以取代,但這並不明顯,這會造成很大的差異。首先發現肇事者。

您也可以存儲正確數量的值,但會引入反規範化。