2016-07-22 7 views
0

私は、次の表にしているSQLコードを最適化するにはどうすればよいですか?

連絡先

contact_id | contact_slug | contact_first_name | contact_email | contact_date_added | company_id | contact_is_active | contact_subscribed | contact_last_name | contact_company | contact_twitter

contact_campaigns

contact_campaign_id | contact_id | contact_campaign_created | company_id | contact_campaign_sent

bundle_feedback

bundle_feedback_id | bundle_id、contact_id | company_id | bundle_feedback_rating | bundle_feedback_favorite_track_id | bundle_feedback_supporting | campaign_id

バンドル

bundle_id | bundle_name | bundle_created | company_id | bundle_is_active

トラック

track_id | company_id | track_title

私はこのクエリを書いていますが、それはゆっくりと動作します。

SELECT SQL_CALC_FOUND_ROWS c.contact_id, 
          c.contact_first_name, 
          c.contact_last_name, 
          c.contact_email, 
          c.contact_date_added, 
          c.contact_company, 
          c.contact_twitter, 
          concat(c.contact_first_name," ", c.contact_last_name) AS fullname, 
          c.contact_subscribed, 
          ifnull(icc.sendCampaignsCount, 0) AS sendCampaignsCount, 
          ifnull(round((ibf.countfeedbacks/sendCampaignsCount * 100),2), 0) AS percentFeedback, 
          ifnull(ibf.bundle_feedback_supporting, 0) AS feedbackSupporting 
FROM contacts AS c 
LEFT JOIN 
    (SELECT c.contact_id, 
      count(cc.contact_campaign_id) AS sendCampaignsCount 
    FROM contacts AS c 
    LEFT JOIN contact_campaigns AS cc ON cc.contact_id = c.contact_id 
    WHERE c.company_id = '876' 
    AND c.contact_is_active = '1' 
    AND cc.contact_campaign_sent = '1' 
    GROUP BY c.contact_id) AS icc ON icc.contact_id = c.contact_id 
LEFT JOIN 
    (SELECT bf.contact_id, 
      count(*) AS countfeedbacks, 
      bf.bundle_feedback_supporting 
    FROM bundle_feedback bf 
    JOIN bundles b 
    JOIN contacts c 
    LEFT JOIN tracks t ON bf.bundle_feedback_favorite_track_id = t.track_id 
    WHERE bf.bundle_id = b.bundle_id 
    AND bf.contact_id = c.contact_id 
    AND bf.company_id='876' 
    GROUP BY bf.contact_id) AS ibf ON ibf.contact_id = c.contact_id 
WHERE c.company_id = '876' 
    AND contact_is_active = '1' 
ORDER BY percentFeedback DESC LIMIT 0, 25; 
+0

避けます。 – Avi

+0

各JOINの後に 'JOIN'節が' ON'節を持つように修正してください。これによりパフォーマンスは向上しませんが、クエリをより理解しやすくなります。 –

+0

あなたは本当にSQLコマンドを改善する必要がありますか?ハッハッハ..ちょうどあなたのビジネスロジックとSQLクエリが大幅に改善される改善する)。 – MaNKuR

答えて

0

私は不必要に二度参加し、最終的にどこの条件で条件を入れてきている連絡先を削除しました)2つの改善

1を行っています。 SQL_CALC_FOUND_ROWS

Which is fastest? SELECT SQL_CALC_FOUND_ROWS FROM `table`, or SELECT COUNT(*)

SELECT      c.contact_id, 
          c.contact_first_name, 
          c.contact_last_name, 
          c.contact_email, 
          c.contact_date_added, 
          c.contact_company, 
          c.contact_twitter, 
          concat(c.contact_first_name," ", c.contact_last_name) AS fullname, 
          c.contact_subscribed, 
          ifnull(icc.sendCampaignsCount, 0) AS sendCampaignsCount, 
          ifnull(round((ibf.countfeedbacks/sendCampaignsCount * 100),2), 0) AS percentFeedback, 
          ifnull(ibf.bundle_feedback_supporting, 0) AS feedbackSupporting 
FROM contacts AS c 
LEFT JOIN 
    (SELECT cc.contact_id, 
      count(cc.contact_campaign_id) AS sendCampaignsCount 
    FROM contact_campaigns 
    WHERE cc.contact_campaign_sent = '1' 
    GROUP BY cc.contact_id) AS icc ON icc.contact_id = c.contact_id 
LEFT JOIN 
    (SELECT bf.contact_id, 
      count(*) AS countfeedbacks, 
      bf.bundle_feedback_supporting 
    FROM bundle_feedback bf 
    JOIN bundles b 
    LEFT JOIN tracks t ON bf.bundle_feedback_favorite_track_id = t.track_id 
    WHERE bf.bundle_id = b.bundle_id 
    GROUP BY bf.contact_id) AS ibf ON ibf.contact_id = c.contact_id 
WHERE c.company_id = '876' and c.contact_is_active = '1' 
0

まずごとに、あなたは、クエリを最適化する必要があるすべてのインデックスを特定していないよう

2)を除去します。つまり、少なくとも次の複合/カバリングインデックスがあることを確認します。あなたが本当に資格行数を必要としない限り、

table    index 
contacts   (company_id, contact_is_active) 
contact_campaigns (contact_id, contact_campaign_sent) 
bundle_feedback (contact_id, bundle_feedback_supporting) 

次は、他の回答で述べたように、「SQL_CALC_FOUND_ROWS」を削除します。

最初の左結合(icc)では、contact_campaigns(cc)に左結合を行いますが、WHERE句に「AND cc.contact_campaign_sent = '1'」を挿入してINNERに変換しますJOIN。外側のクエリレベルでは、一致するレコードがないため、パーセンテージの計算にNULLが返されます。

2番目の左結合(ibf)では、トラックテーブルへの結合を行っていますが、そこから何も利用していません。また、バンドルテーブルに参加していますが、そこから何も使用していません。バンドル内で複数の行を取得し、テーブルを追跡してデカルト結果になり、 "CountFeedbacks"値を過大評価する場合を除きます。連絡先テーブルは他に何もしていないので、連絡先テーブルは必要ありません。また、フィードバックテーブルには問い合わせ先の連絡先IDがあります。それはcontact_idによってグループ化されるだけなので、あなたの "bf.bundle_feedback_supporting"は無駄になります。フィードバックのカウントが必要な場合は、連絡先IDごとにそのテーブルからカウントし、残りを削除します。(また、一貫性のために、結合にはWHERE句の代わりに "ON"句を使用する必要があります)

また、サポートのフィードバックとして、データ型と値が不明なので、私はYesまたはNoとして暗示しています。サポートしている数に基づくSUM()。したがって、特定の連絡先には100件のレコードが含まれていますが、37件のみがサポートしています。これにより、BOTHの値がそれぞれ100と37で、連絡先の最初のエントリに基づいてグループ内で失われていない連絡先のレコードが1件表示されます。

私は以下のクエリを要約しようとするだろう。それは、レコードの膨大な数が含まれてあまりにもあれば、複数のテーブルに数回参加

SELECT 
     c.contact_id, 
     c.contact_first_name, 
     c.contact_last_name, 
     c.contact_email, 
     c.contact_date_added, 
     c.contact_company, 
     c.contact_twitter, 
     concat(c.contact_first_name," ", c.contact_last_name) AS fullname, 
     c.contact_subscribed, 
     ifnull(icc.sendCampaignsCount, 0) AS sendCampaignsCount, 
     ifnull(round((ibf.countfeedbacks/icc.sendCampaignsCount * 100),2), 0) AS percentFeedback, 
     ifnull(ibf.SupportCount, 0) AS feedbackSupporting 
    FROM 
     contacts AS c 

     LEFT JOIN 
     (SELECT 
       c.contact_id, 
       count(*) AS sendCampaignsCount 
       FROM 
       contacts AS c 
        JOIN contact_campaigns AS cc 
         ON c.contact_id = cc.contact_id 
         AND cc.contact_campaign_sent = '1' 
       WHERE 
        c.company_id = '876' 
       AND c.contact_is_active = '1' 
       GROUP BY 
       c.contact_id) AS icc 
      ON c.contact_id = icc.contact_id 

     LEFT JOIN 
     (SELECT 
       bf.contact_id, 
       count(*) AS countfeedbacks, 
       SUM(case when bf.bundle_feedback_supporting = 'Y' 
          then 1 else 0 end) as SupportCount 
       FROM 
       contacts AS c 
        JOIN bundle_feedback bf 
         ON c.contact_id = bf.contact_id 
       WHERE 
        c.company_id = '876' 
       AND c.contact_is_active = '1' 
       GROUP BY 
       bf.contact_id) AS ibf 
      ON c.contact_id = ibf.contact_id 
    WHERE 
      c.company_id = '876' 
     AND c.contact_is_active = '1' 
    ORDER BY 
     percentFeedback DESC LIMIT 0, 25; 
関連する問題