2012-04-24 121 views
2

我緩慢查詢緩存與memcached,它很好,但有時我們在mysql中有很多緩慢的查詢,就像memcached已停止,然後我們的網站關閉。MySQL緩慢查詢和memcached

慢查詢圖:http://i.imgur.com/ReyWe.png

在這個時刻,我們在30秒內得到約100慢查詢。它可能是什麼? 我們查詢:

# Query_time: 5.942602 Lock_time: 0.010214 Rows_sent: 10000 Rows_examined: 493139 

SET timestamp=1335194149; 
SELECT story_id FROM dug_stories d WHERE d.story_is_permanent=0 AND 
         ( 
         (d.story_time>1335190543 AND (d.story_pluses-d.story_minuses) > 5) 
         OR 
         (((d.story_pluses-d.story_minuses) > 12 OR (d.story_pluses >= 10 AND d.story_minuses<=0)) AND d.story_cat!=48 AND d.st 
ory_cat!=131 AND d.story_cat!=55 AND d.story_cat!=44 AND d.story_cat!=126 AND d.story_cat!=53 AND d.story_cat!=370 AND d.story_cat!=381 AND d.stor 
y_cat!=304 AND d.story_cat!=497) OR (d.story_cat=48 AND (d.story_pluses-d.story_minuses) > 9) OR (d.story_cat=131 AND (d.story_pluses-d.story_min 
uses) > 8) OR (d.story_cat=55 AND (d.story_pluses-d.story_minuses) > 8) OR (d.story_cat=44 AND (d.story_pluses-d.story_minuses) > 9) OR (d.story_c 
at=126 AND (d.story_pluses-d.story_minuses) > 13) OR (d.story_cat=53 AND (d.story_pluses-d.story_minuses) > 8) OR (d.story_cat=370 AND (d.story_pl 
uses-d.story_minuses) > 8) OR (d.story_cat=381 AND (d.story_pluses-d.story_minuses) > 8) OR (d.story_cat=304 AND (d.story_pluses-d.story_minuses) 
> 8) OR (d.story_cat=497 AND (d.story_pluses-d.story_minuses) > 9) 
         ) 
         ORDER BY d.story_rating DESC, d.story_time DESC LIMIT 0, 10000; 



小幅調整查詢(而不是全部=類別,我更改爲不類別中(要排除的類別)的名單,但格式,可讀性更強! ......另外,還要注意的SET TIMESTAMP變量甚至沒有被查詢中使用的...這是一個硬編碼值。

SET timestamp=1335194149; 
SELECT 
     story_id 
    FROM 
     dug_stories d 
    WHERE 
      d.story_is_permanent = 0 
     AND ( (d.story_time > 1335190543 AND d.story_pluses - d.story_minuses > 5) 
      OR ( ( d.story_pluses - d.story_minuses > 12 
         OR ( d.story_pluses >= 10 AND d.story_minuses <= 0) 
        ) 
        AND NOT d.story_cat IN (44, 48, 53, 55, 126, 131, 304, 370, 381, 497) 
       ) 
      OR (d.story_cat = 44 AND d.story_pluses - d.story_minuses > 9) 
      OR (d.story_cat = 48 AND d.story_pluses - d.story_minuses > 9) 
      OR (d.story_cat = 53 AND d.story_pluses - d.story_minuses > 8) 
      OR (d.story_cat = 55 AND d.story_pluses - d.story_minuses > 8) 
      OR (d.story_cat = 126 AND d.story_pluses - d.story_minuses > 13) 
      OR (d.story_cat = 131 AND d.story_pluses - d.story_minuses > 8) 
      OR (d.story_cat = 304 AND d.story_pluses - d.story_minuses > 8) 
      OR (d.story_cat = 370 AND d.story_pluses - d.story_minuses > 8) 
      OR (d.story_cat = 381 AND d.story_pluses - d.story_minuses > 8) 
      OR (d.story_cat = 497 AND d.story_pluses - d.story_minuses > 9) 
     ) 
    ORDER BY 
     d.story_rating DESC, 
     d.story_time DESC 
    LIMIT 
     0, 10000; 

非常感謝您的幫助! 對不起,我的英文不好:)

回答

0

如果rows_examined大於結果集,緩慢的日誌可能表明索引沒有被充分利用。

理想情況下,MySQL應該能夠在WHERE子句中爲所有過濾器表達式使用單個索引。由於所有嵌套的AND和OR以及對多個列的引用,您的WHERE子句非常複雜。 MySQL可能無法利用索引來優化此查詢,即使您有一個。

通常,可以通過將這種類型的查詢分成幾個較小的查詢來改進,每個查詢都能夠使用索引,並使用UNION將結果組合成單個查詢。

舉例來說,如果我有FIRST_NAME的索引和姓氏索引,下面的查詢:

SELECT * 
FROM Users 
WHERE active = true 
    AND ((first_name = 'Marcus') OR (last_name = 'Adams')) 

可以這樣改進:

SELECT * 
FROM Users 
WHERE active = true 
    AND first_name = 'Marcus' 
UNION 
SELECT * 
FROM Users 
WHERE active = true 
    AND last_name = 'Adams' 

事實上,有更多的在您的LIMIT子句中檢查的行數超過10000也表示ORDER BY子句可能正在使用文件排序,而不是查詢已按順序返回行。這使得MySQL可以完成所有的工作,即使你只需要一部分記錄。您很可能需要利用覆蓋索引來處理您的所有條件,這可能是不可能的,或者您需要刪除ORDER BY子句,或者如您所述,依靠緩存來節省一天。

對於高負載的服務器,查詢時間是一個糟糕的性能測量,因爲任何查詢在繁忙的服務器上可能會很慢。您應該使用EXPLAINSHOW PROFILE來分析您的查詢並對其進行改進,以便它們不會對服務器造成太大負擔。

允許太多線程在服務器上運行可能會導致級聯效應,導致服務器停止。如果您使用的是InnoDB,請確保您的thread concurrency不是太高。最好讓每個人一次等待並提供8個線程(非常快),而不是一次嘗試提供100個或無限的線程(非常慢)。

+0

非常感謝!我會試試:) – dalopikz 2012-04-24 14:29:21

0

除了調整查詢的可讀性以外,我會嘗試重新構建查詢。
我會確保你有一個索引(Story_Is_Permanent,Story_Cat,Story_Time)

我會假設你有一個「故事類別」表的文字描述呈現給用戶。由於您無論如何都在查詢所有類別,但僅基於某些您想要的INCLUDE或EXCLUDE ...,如果包含,則僅基於該類別的PLUSES和MINUSES的淨計數。我想補充到列該類別表...像

DefaultToInclude integer as 1 or 0 
PlusMinusNetCount integer 

然後,做了一個連接以類別表,並簡化您的查詢,像

SELECT 
     story_id 
    FROM 
     dug_stories d 
     JOIN YourCategories YC 
      on d.story_cat = YC.categoryID 
    WHERE 
      d.story_is_permanent = 0 
     AND ( (d.story_time > 1335190543 AND d.story_pluses - d.story_minuses > 5) 
      OR ( YC.DefaultToInclude = 0 
        AND ( d.story_pluses - d.story_minuses > 12 
         OR (d.story_pluses >= 10 AND d.story_minuses <= 0) 
        ) 
       ) 
      OR ( YC.DefaultToInclude = 1 
        AND d.story_pluses-d.story_minuses > YC.PlusMinusNetCount) 
     ) 
ORDER BY 
     d.story_rating DESC, 
     d.story_time DESC 
    LIMIT 
     0, 10000; 




The

( YC.DefaultToInclude = 0 
    AND ( d.story_pluses - d.story_minuses > 12 
     OR (d.story_pluses >= 10 AND d.story_minuses <= 0) 
    ) 
) 

最終將取代

OR ( ( d.story_pluses - d.story_minuses > 12 
      OR ( d.story_pluses >= 10 AND d.story_minuses <= 0) 
     ) 
    AND d.story_cat!=48 
    AND d.story_cat!=131 
    AND d.story_cat!=55 
    AND d.story_cat!=44 
    AND d.story_cat!=126 
    AND d.story_cat!=53 
    AND d.story_cat!=370 
    AND d.story_cat!=381 
    AND d.story_cat!=304 
    AND d.story_cat!=497 
    ) 

OR ( YC.DefaultToInclude = 1 
     AND d.story_pluses-d.story_minuses > YC.PlusMinusNetCount) 

隨後將最終替換

(OR (d.story_cat = 44 AND d.story_pluses - d.story_minuses > 9) 
    OR (d.story_cat = 48 AND d.story_pluses - d.story_minuses > 9) 
    OR (d.story_cat = 53 AND d.story_pluses - d.story_minuses > 8) 
    OR (d.story_cat = 55 AND d.story_pluses - d.story_minuses > 8) 
    OR (d.story_cat = 126 AND d.story_pluses - d.story_minuses > 13) 
    OR (d.story_cat = 131 AND d.story_pluses - d.story_minuses > 8) 
    OR (d.story_cat = 304 AND d.story_pluses - d.story_minuses > 8) 
    OR (d.story_cat = 370 AND d.story_pluses - d.story_minuses > 8) 
    OR (d.story_cat = 381 AND d.story_pluses - d.story_minuses > 8) 
    OR (d.story_cat = 497 AND d.story_pluses - d.story_minuses > 9) 
) 

這可以靈活地簡單地包含/排除其他類別與其各自的「淨」數量,而無需爲您已經冗長的查詢添加更多的OR/AND條件。毫無疑問,它看起來總是需要經歷整個「dug_Stories」表,因爲您正在查看每個類別的一個條件,以及每個其他類別的另一個類別。您的時間戳記僅適用於NOT EQUAL類別,但您的其他條件沒有任何時間戳記限制(除非您的查詢中存在錯誤)。

+0

謝謝! )首先我會盡量減少LIMIT,希望這可以幫助... – dalopikz 2012-04-25 10:46:28