2016-12-31 81 views
-2

我正面臨着SQL查詢的問題。我正在開發一個PHP的網站,並避免讓太多的疑問,我寧願做一個大一個看起來像:SQL查詢需要太多時間(3個連接)

 select m.*, cj.*, cjb.*, me.pseudo as pseudo_acheteur 
     from mercato m 
     JOIN cartes_joueur cj 
     ON m.ID_carte = cj.ID_carte_joueur 
     JOIN cartes_joueur_base cjb 
     ON cj.ID_carte_joueur_base = cjb.ID_carte_joueur_base 
     JOIN membres me 
     ON me.ID_membre = cj.ID_membre 
     where not exists (select * from mercato_encheres me where me.ID_mercato = m.ID_mercato) 
     and cj.ID_membre = 2 
     and m.status <> 'cancelled' 
     ORDER BY total_carac desc, cj.level desc, cjb.nom_carte asc 

這應該返回由會員銷售的所有卡上沒有任何賭注。結果,我需要所有的信息來顯示它們。

下面是每個表中的近似行:

  • 梅爾卡託:1200

  • cartes_joueur:800 000

  • carte_joueur_base:62
  • membres:2000
  • mercato_enchere:15 000

我試圖通過刪除舊數據來減少它們(在開發環境中)但查詢仍然需要10〜15秒才能執行(這在網站上太長了)

感謝您的幫助。

+0

解釋計劃告訴你什麼? –

+1

我猜子查詢是問題所在。嘗試將其更改爲外部聯接,並檢查一個字段是否爲空。 – Sirko

+2

請參閱http://meta.stackoverflow.com/questions/333952/why-should-i-provide-an-mcve-for-what-seems-to-me-to-be-a-very-simple-sql-查詢。此外,對於有關查詢優化的問題,我們將在適當的時候看到EXPLAIN。但讓我們先查詢一下 – Strawberry

回答

0

讓我們來看看。

  1. 採用*SELECT條款是有害的查詢性能。爲什麼?這是浪費。它不必要地增加了服務器必須處理的數據量,並且在JOIN的情況下,可以強制處理具有重複值的列。如果可能,可以嘗試枚舉所需的列。

  2. 您可能沒有有用的索引在您的表加速這一點。我們不知道。請注意,MySQL不能在單個查詢中利用多個索引,因此爲了快速查詢,您通常需要一個精心挑選的複合索引。我建議您嘗試在cartes_joueur表上定義索引(ID_membre, ID_carte_jouer, ID_carte_joueur_base)。爲什麼?您的查詢在這些列的第一列上匹配相等,然後在ON條件中使用第二列和第三列。

  3. 我經常發現用最大的表格編寫一個查詢(大多數行)首先幫助我清楚地考慮優化。在你的情況下,你的最大表格是cartes_jouer,並且你正在從該表格中選擇一個ID_membre值。您最清楚的優化路徑是您只需要檢查該表中大約400行而不是800 000的知識。合適的複合索引將使這成爲可能,並且如果表中的查詢最先出現,那麼想象該索引的列是最容易的。

  4. 你有一個相關的子查詢 - 這一個。它看到這個的時候,運行它上千次

    where not exists (select * 
            from mercato_encheres me 
            where me.ID_mercato = m.ID_mercato) 
    

MySQL的查詢規劃可能是愚蠢的迂。在你的情況下,情況更糟:其中有SELECT *:見上面的第1點。

它應該被重構爲使用LEFT JOIN ... IS NULL模式。這是怎麼回事。

select whatever 
    from mercato m 
    JOIN ... 
    JOIN ... 
    LEFT JOIN mercato_encheres mench ON mench.ID_mercato = m.ID_mercato 
    WHERE mench.ID_mercato IS NULL 
    and ... 
    ORDER BY ... 

說明:使用LEFT JOIN而不是普通的內JOIN允許從mercato錶行輸出被保留,即使接通狀態並不在mercato_encheres表它們匹配表。不匹配的行獲得第二個表的NULL值。 WHERE子句中的mench.ID_mercato IS NULL條件然後選擇只有不匹配的行。