2017-05-17 16 views
1

私は(それは約10秒かかりgstatsテーブルは私の開発環境では約130K行を持っており、生産にはるかに大きいです。)期待される結果が得られますが、非常に遅いです、次のクエリを持っている:HAVING句を使用したクエリの処理が遅くなる可能性がありますか?

SELECT count(d.id) AS dcount, s.id, s.name 
FROM sites s 
LEFT JOIN deals d ON (s.id = d.site_id AND d.is_active = 1) 
WHERE (s.is_active = 1) 
AND s.id IN(
    SELECT g.site_id 
    FROM gstats g 
    WHERE g.start_date > '2015-04-30' 
    GROUP BY g.site_id 
    HAVING SUM(g.results) > 100 
) 
GROUP BY s.id 
ORDER BY dcount ASC 

アム私は何か間違っている?どうすればこれをスピードアップできますか?

は、ビューのヘルプを使用して/インデックスを追加しますか?

+0

クエリの前に 'explain'を追加して実行し、結果を私たちと共有できますか? それは –

答えて

1

クイックフィックスは、サブクエリでフィルタに次のようになります。

SELECT count(d.id) AS dcount, s.id, s.name 
FROM sites s 
LEFT JOIN deals d ON (s.id = d.site_id AND d.is_active = 1) 
WHERE (s.is_active = 1) 
AND s.id IN(
    SELECT g.site_id 
    FROM gstats g 
    WHERE g.start_date > '2015-04-30'AND g.site_id = s.id 
    GROUP BY g.site_id 
    HAVING SUM(g.results) > 100 
) 
GROUP BY s.id 
ORDER BY dcount ASC

そうでないので、あなたはすべての可能な候補のために、このようなグループ化のクエリを実行します。今、私たちはすべての要素にEXISTSを使用しますが、

SELECT count(d.id) AS dcount, s.id, s.name 
FROM sites s 
LEFT JOIN deals d ON (s.id = d.site_id AND d.is_active = 1) 
WHERE (s.is_active = 1) 
AND EXISTS ( SELECT 1 FROM gstats g WHERE g.site_id = s.id AND g.start_date > '2015-04-30' HAVING SUM(g.results) > 100 ) 
GROUP BY s.id 
ORDER BY dcount ASC

しかし、我々はまだ終わっていません。私たちは、EXISTSでこれよりエレガントにすることができます。クエリーはs.idにのみ依存するため、それは奇妙なので、グループにのみ依存し、個々の行には依存しません。だから、可能性スピードアップが、これはなど、テーブルのサイズに依存してはHAVINGの文に条件を移動することです:

SELECT count(d.id) AS dcount, s.id, s.name 
FROM sites s 
LEFT JOIN deals d ON (s.id = d.site_id AND d.is_active = 1) 
WHERE (s.is_active = 1) 
GROUP BY s.id 
ORDER BY dcount ASC 
HAVING EXISTS (
    SELECT 1 
    FROM gstats g 
    WHERE g.site_id = s.id AND g.start_date > '2015-04-30' 
    HAVING SUM(g.results) > 100 
)
+0

など、クエリの実行計画を示し、それがインデックスと場所ではないが使っているところを示していますし、どのように多くの行がスキャンされるありがとう:)これは完全に働いた、それが今の私のdevの環境に30ミリ秒のようなものを取る - 好奇心から:何を私もその合計(g.results)を選択したいのですか? – koichirose

1

FROM句にサブクエリを移動してみてください:

SELECT count(d.id) AS dcount, s.id, s.name 
FROM sites s JOIN 
    (SELECT g.site_id 
     FROM gstats g 
     WHERE g.start_date > '2015-04-30' 
     GROUP BY g.site_id 
     HAVING SUM(g.results) > 100 
    ) g 
    ON g.site_id = s.site_id LEFT JOIN 
    deals d 
    ON s.id = d.site_id AND d.is_active = 1 
WHERE s.is_active = 1 
GROUP BY s.id 
ORDER BY dcount ASC; 

join列にインデックスがあると仮定します。また、これはパフォーマンスが向上しますことがあります:このバージョンのために

SELECT s.id, s.name, 
     (SELECT COUNT(*) 
     FROM deals d 
     WHERE d.site_id = s.id AND d.is_active = 1 
     ) as dcount 
FROM sites s JOIN 
    (SELECT g.site_id 
     FROM gstats g 
     WHERE g.start_date > '2015-04-30' 
     GROUP BY g.site_id 
     HAVING SUM(g.results) > 100 
    ) g 
    ON g.site_id = s.site_id 
WHERE s.is_active = 1 
ORDER BY dcount ASC; 

、あなたがdeals(site_id, is_active)にインデックスをしたいです。

+0

これも正しい答えでしょう。それは私のために働くが、サブクエリーでJOINステートメントをサポートしていないDoctrineを使用している。 – koichirose

0

クエリはそのまま正常に表示されます。

create index idx_gstats on gstats(start_date, results, site_id); 
create index idx_deals1 on deals(is_active, site_id); 
create index idx_deals2 on deals(site_id, is_active); 

次に、使用されない取引インデックスを削除します。

関連する問題