2013-03-29 33 views
2

我有一個SQL查詢(見下文),返回我需要的,但是當通過phpMyAdmin運行需要從0.0009秒到0.1149秒,偶爾一直到7.4983秒。爲什麼MySQL查詢需要從1毫秒到7秒的任何地方?

查詢:

SELECT 
    e.id, 
    e.title, 
    e.special_flag, 
    CASE WHEN a.date >= '2013-03-29' THEN a.date ELSE '9999-99-99' END as date 
    CASE WHEN a.date >= '2013-03-29' THEN a.time ELSE '99-99-99' END as time, 
    cat.lastname, 
    FROM e_table as e 
    LEFT JOIN a_table as a ON (a.e_id=e.id) 
    LEFT JOIN c_table as c ON (e.c_id=c.id) 
    LEFT JOIN cat_table as cat ON (cat.id=e.cat_id) 
    LEFT JOIN m_table as m ON (cat.name=m.name AND cat.lastname=m.lastname) 
    JOIN (
      SELECT DISTINCT innere.id 
      FROM e_table as innere 
      LEFT JOIN a_table as innera ON (innera.e_id=innere.id AND 
              innera.date >= '2013-03-29') 
      LEFT JOIN c_table as innerc ON (innere.c_id=innerc.id) 
      WHERE (
        (
        innera.date >= '2013-03-29' AND 
        innera.flag_two=1 
       ) OR 
        innere.special_flag=1 
       ) AND 
       innere.flag_three=1 AND 
       innere.flag_four=1 
      ORDER BY COALESCE(innera.date, '9999-99-99') ASC, 
        innera.time ASC, 
        innere.id DESC LIMIT 0, 10 
     ) AS elist ON (e.id=elist.id) 
    WHERE (a.flag_two=1 OR e.special_flag) AND e.flag_three=1 AND e.flag_four=1 
    ORDER BY a.date ASC, a.time ASC, e.id DESC 

解釋計劃: The above query explain plan

的問題是: 此查詢的一部分可能會造成大範圍的性能差異?

+0

你能後的上

(id, flag_three, flag_four, special_flag). 

對於「一」表,索引的索引解釋計劃? – Taryn

+0

你有一個索引上的所有連接列(a.e_id,e.id,c.id,e.cat_id))和過濾列(a.flag_two,e.special_flag,e.flag_three? –

+0

@bluefeet我我」將不得不穀歌如何做到這一點,我會一次我想出如何讓「解釋計劃」 –

回答

4

要特別回答你的問題:它不是查詢的具體部分,導致廣泛的性能。這就是MySQL做它應該做的事 - 作爲關係數據庫管理系統(RDBMS),而不僅僅是逗號分隔文件周圍的一個愚蠢的SQL包裝。

當你執行一個查詢,下面的事情發生:

  1. 查詢被編譯成一個「參數化」的查詢,消除所有變量下降到純粹的結構SQL。
  2. 檢查編譯緩存以查找是否爲查詢找到最近可用的執行計劃。
  3. 該查詢被編譯成如果需要的話執行計劃(這是什麼「解釋」所示)
  4. 對於每個執行計劃元件,所述存儲器緩存被檢查是否含有新鮮和可用的數據,否則該中間數據是從主表數據彙編。
  5. 通過將所有中間數據放在一起來組裝最終結果。

你所看到的是,當查詢成本0.0009秒,緩存是足夠新鮮的所有數據供應在一起,當峯值爲7.5秒無論是什麼東西被查詢表中的變化,或其他查詢「推送'內存中緩存數據,或者DBMS有其他理由懷疑需要重新編譯查詢或再次獲取所有數據。也許其他一些變化可能與已使用的索引仍然在內存中足夠新鮮或不足。

總結這一點,查詢速度很慢,你有時很幸運,緩存使它顯得很快。

爲了解決這個問題,我建議考慮兩件事情:

  1. 首先 - 查詢這種規模不應該在其執行計劃閱讀「沒有可能的密鑰」一行。研究索引如何工作,確保你意識到MySQL對每個連接表使用單個索引的限制的影響,並調整數據庫,以使計劃的每一行都在「關鍵」下有一個條目。
  2. 其次,查看本身的查詢。當他們所要做的就是結合原始數據時,DBMS的速度是最快的。使用編程元素CASECOALESCE通常都是有用的,但它們確實會強制數據庫在運行時評估更多事情,而不僅僅是獲取原始表數據。嘗試消除這些語句,或將它們移動到業務邏輯中作爲對檢索數據的後處理。

最後,永遠不要忘記MySQL實際是一個相當愚蠢的DBMS。它針對大多數網站要求的簡單數據提取查詢進行了優化。因此,對於大多數通用問題,它比SQL Server和Oracle快得多。一旦你開始用函數,案例,巨大的連接或匹配條件等使事情複雜化,競爭對手通常會更好地進行優化,並且在查詢編譯器中有更好的優化。因此,當MySQL在特定查詢中開始變慢時,考慮將它分成2個或更多更小的查詢,以便它不會混淆,然後在PHP中進行一些後處理,或者使用您調用的任何語言進行後處理。我看到很多情況下,這種性能提升很多,只是不會混淆MySQL,特別是在涉及子查詢的情況下(如您的情況)。特別是你的子查詢是一個派生表,而不僅僅是一個子查詢,這一事實被認爲會讓MySQL的東西超出它可以應付的範圍。

+0

謝謝你回答這個問題! –

1

讓我們開始您的外部查詢和內部查詢都與「e」表一起工作,並且最低要求爲flag_three = 1且flag_four = 1(無論您的內部查詢((x和y)或z)條件如何。另外,你的外部WHERE子句有對a.Flag_two的明確引用,但是沒有NULL強制你的LEFT JOIN實際上變成一個(INNER)JOIN。並且,每一個「e」記錄都必須有一個類別,你正在尋找如果沒有找到「cat.lastname」並且沒有coalesce(),這是有意義的,它似乎是一個「查找」表引用。至於「m_table」和「c_table」,你沒有得到或做任何事情,這樣他們就可以被完全清除。

請問以下查詢你得到同樣的結果?

select 
     e1.id, 
     e1.Title, 
     e1.Special_Flag, 
     e1.cat_id, 
     coalesce(a1.date, '9999-99-99') ADate, 
     coalesce(a1.time, '99-99-99') ATime 
     cat.LastName 
    from 
     e_table e1 
     LEFT JOIN a_table as a1 
      ON e1.id = a1.e_id 
      AND a1.flag_two = 1 
      AND a1.date >= '2013-03-29' 

     JOIN cat_table as cat 
      ON e1.cat_id = cat.id 
    where 
      e1.flag_three = 1 
     and e1.flag_four = 1 
     and ( e1.special_flag = 1 
      OR a1.id IS NOT NULL) 
    order by 
     IF(a1.id is null, 2, 1), 
     ADate, 
     ATime, 
     e1.ID Desc 
    limit 
     0, 10 

主WHERE子句限定爲只有那些有「三,四」的標誌設置爲1 PLUS是(特殊標誌存在,或者有一個有效的「A」記錄是在/在指定日期之後有問題)。

從那,簡單的順序和限制。

至於獲取日期和時間,看起來您只希望包含日期/之後的記錄,否則忽略它們(例如它們過時並且不適用,您不希望看到它們) 。

的,我先試爲「一」 ID NULL值的順序。如果是這樣,我們知道他們將被迫到'9999-99-99'的日期和'99-99-99'的時間,並且希望他們被推到底部(因此2),否則,就有一個「a 「記錄,你想要那些第一(因此1)。然後,分別按日期/時間排序,然後在相同日期/時間內排序很多情況下的ID。

最後,以幫助索引,我會確保你的「e」表上

(e_id, flag_two, date) 
+0

感謝您花時間回覆!不幸的是,你提供的查詢沒有返回我想要的。我不只想要10件事,我希望table_e中的所有東西最多匹配table_e的10個獨特的東西。我將使用您建議的索引調查查詢性能。 –