如何优化我的sql代码?

时间:2016-07-22 10:41:55

标签: mysql 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;

2 个答案:

答案 0 :(得分:0)

我做了2次改进

1)删除不必要地连接两次的联系人,并将条件置于最终条件。

2)根据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'

答案 1 :(得分:0)

首先,您没有确定优化查询所需的任何索引。也就是说,我会确保您至少拥有以下复合/覆盖索引。

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。

在你的第二个左连接(ibf)中,你正在连接到轨道表,但没有使用它的任何东西。此外,您正在加入bundle表但不使用其中的任何内容 - 除非您在bundle中获取多行并跟踪表,这将导致笛卡尔结果并可能夸大您的“CountFeedbacks”值。您也不需要联系人表,因为您没有对其进行任何其他操作,反馈表具有您要查询的联系人ID。由于这只是按contact_id分组,否则您的“bf.bundle_feedback_supporting”会被浪费掉。如果您需要反馈计数,只需从每个联系人ID的表中计算并删除其余的。 (另外,连接应该具有“ON”子句而不是WHERE子句中的一致性)

另外,对于您的支持反馈,数据类型和值不清楚,因此我暗示为是或否,并根据有多少人支持SUM()。因此,给定的联系人可能有100条记录,但只有37条支持。这将为您提供1条记录,分别为BOTH值为100和37,并且不会在基于找到该联系人的第一个条目的组中丢失。

我会尝试将您的查询汇总到下面:

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;