2013-03-26 142 views
2

首先,我對此問題的「新手」式性質表示歉意。我在堆棧交換中看到了許多其他緩慢子查詢的問題,但我不確定如何將修復應用於我的問題。我是相當新的超越簡單的選擇,插入任何SQL等SQL - 緩慢子查詢

我有記錄其結果到MySQL表(trends_uint)每五分鐘了各種設備的打印機監控系統。它記錄:設備ID(itemid),時間戳(時鐘)和打印的頁面(value_avg)。從PhpMyAdmin我可以看到表索引是itemid和clock的組合,我猜測它們共同提供了一個獨特的值。到目前爲止,這個表有大約200萬行。

我的查詢如下:

SELECT 
    tu1.itemid AS trends_uint_itemid, 
    tu1.clock AS time_value, 
    tu1.value_avg AS pages 
FROM 
    trends_uint tu1 
WHERE 
    (tu1.clock = (
        SELECT max(tu2.clock) 
        FROM trends_uint tu2 
        WHERE tu1.itemid = tu2.itemid 
       ) 
    ) 
ORDER BY tu1.clock DESC; 

我想要做的,就是選擇了最新的值(即value_avg的最高時鐘)爲每個設備(itemid的),所以我可以希望繪製出每臺打印機到目前爲止打印的頁數。

我試着運行它返回以下查詢的EXPLAIN:

id select_type   table type possible_keys key   key_len  ref     rows  Extra 
1 PRIMARY    tu1  ALL  NULL   NULL  NULL  NULL    1527815  Using where; Using filesort 
2 DEPENDENT SUBQUERY tu2  ref  PRIMARY   PRIMARY  8   zabbix.tu1.itemid 115301  Using index 

任何幫助,將不勝感激。提前致謝。

回答

0

如果使用明確的子查詢,它會有所作爲嗎?

SELECT 
    tu1.itemid AS trends_uint_itemid, 
    tu1.clock AS time_value, 
    tu1.value_avg AS pages 
FROM 
    trends_uint tu1 
JOIN 

(
    SELECT 
     itemid as theItem 
     ,max(tu2.clock) AS LatestTime 
    FROM trends_uint tu2 
    GROUP BY itemid 
) LatestClockForEachItem 

ON tu1.itemid = LatestClockForEachItem.theItem 
AND tu1.clock = LatestClockForEachItem.LatestTime 

ORDER BY tu1.clock DESC; 

PS。 SQL小提琴在這裏:http://sqlfiddle.com/#!2/bac3b/2

+0

這樣做訣竅:)。感謝您的及時答覆,並鏈接到SQL小提琴。我知道那裏有一個JS Fiddle網站,所以我應該爲了一個SQL小提琴而獵殺:) – Vasudaprime 2013-03-26 14:11:42

1

怎麼樣這樣的查詢:

SELECT ... 
FROM trends_uint t 
INNER JOIN (
    SELECT MAX(clock) AS clock, itemid 
    FROM trends_uint 
    GROUP BY itemid 
) x ON x.itemid = t.itemid AND t.clock = x.clock 

假設你已經在你的表中的複合索引:itemid + clock(在這個特定的順序)

+0

該解決方案還工作過。感謝您的提示答案:)。 – Vasudaprime 2013-03-26 14:12:43

+0

@Vasudaprime:我在9分鐘之前給出了這個答案 - 它和查詢完全相同 – zerkms 2013-03-26 19:37:34

0

的問題是,子查詢的類型是「依賴子查詢「。這意味着MySQL正在爲主查詢的每個匹配行運行該子查詢一次。如果你說表有200萬行意味着大約200萬次。

嘗試使用Group By運算符或使用連接將子查詢的邏輯移至主查詢。

+0

**在內部的mysql中的EVERY **子查詢被重寫(通過優化器)到一個相關的子查詢中(儘管由於某種原因,我無法快速找到證據爲此;但我記得我已經在一些有信譽的來源閱讀過) – zerkms 2013-03-26 11:16:59

+0

我應該詳細說明,作爲一個從屬子查詢,它引用與外部查詢中相同的表。這意味着它必須對來自外部查詢的每個可能的組合進行一次評估。由於子查詢where子句引用了可能是主鍵的item_id,因此對於表中的每個記錄來說這意味着一次。 – 2013-03-26 11:24:11

+0

是的,我知道。這是一篇關於內部事物的文章,它指出甚至不相關的子查詢都被優化器重寫爲相關的子查詢。有一個可能性,只有在子查詢執行得很糟糕的舊版本中才有效。 – zerkms 2013-03-26 11:25:32

0

您的查詢是好的。您需要trends_uint(itemid, clock)上的索引。

您也可以制定子查詢爲:

tu1.clock = (
        SELECT tu2.clock 
        FROM trends_uint tu2 
        WHERE tu1.itemid = tu2.itemid 
        order by tu2.clock desc 
        limit 1 
       ) 

馬,這種形式使得它更清晰的指標如何被使用(進入指數的項目,選擇最後一個時鐘值)。

我還建議你包括表自動遞增的ID作爲主鍵。這可以幫助您加快查詢,試圖獲取表中最近的行。