2016-12-31 8 views
-2

SQLクエリに問題があります。これは、その上の任意の賭けずにメンバーから販売されているすべてのカードを返す必要があります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 

:私は、私はのように見える大きなものを作ることを好む、PHPのWebサイトを開発していて、あまりにも多くのクエリを避けるために。その結果、私はそれらを表示するためにすべての情報が必要です。

  • メルカート:1200

  • cartes_joueur:800 000

  • carte_joueur_base:62
  • membres 2000
  • ここでは、各テーブルの近似列でありますmercato_enchere:15 000

古いデータを削除して(開発環境で)それらを縮小しようとしました。クエリはまだ実行するのに10〜15秒必要です(これはウェブサイトでは長すぎます)

ありがとうございました。

+0

説明プランはあなたに何を伝えますか? –

+1

サブクエリが問題だと思います。それを外部結合に変更して、1つのフィールドを後方にnullにチェックしてみてください。 – 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条件で2番目と3番目の列を使用します。

  3. 私はしばしば、最大のテーブル(ほとんどの行)でクエリを書くと、まず最適化について明確に考えるのに役立ちます。あなたのケースでは、あなたの最大のテーブルはcartes_jouerであり、そのテーブルからただ一つのID_membreの値を選択しています。最適化への最善の道は、800 000ではなく、そのテーブルから約400行を調べるだけでよいという知識です。適切な複合インデックスが可能になります。クエリの最初のテーブルがインデックスの列であると想定するのが最も簡単です。

  4. 相関サブクエリ - これは1つです。それはそれを何千回も実行し、これを見たときに

    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 ... 

説明:むしろ、通常、内側JOINよりLEFT JOINの使用はmercatoテーブルから行がON状態がmercato_encheresテーブルのテーブルにそれらと一致しない場合であっても出力に保存されることを可能にします。不一致の行は、2番目の表のNULL値を取得します。 WHERE句内のmench.ID_mercato IS NULL条件では、の不一致行のみが選択されます。

関連する問題