繁体   English   中英

如何优化我的sql代码?

[英]How can I optimize my sql code?

我有下表

联络人

contact_id | contact_slug | contact_first_name | contact_email | contact_date_added | company_id | contact_is_active | 已订阅| 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处改善

1)移除不必要的两次接触,并将条件置于最终的where条件。

2)已根据SQL_CALC_FOUND_ROWS删除

哪个最快? 从“表”中选择SQL_CALC_FOUND_ROWS,或选择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'

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

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)中,您正在联接到tracks表,但没有使用表中的任何东西。 另外,您正在连接到bundles表,但也不使用那里的任何东西-除非您在bundles和track表中获得多行,这将导致笛卡尔结果,并可能高估“ CountFeedbacks”值。 您也不需要联系人表,因为您无需对其进行任何其他操作,并且反馈表具有您要查询的联系人ID基础。 由于仅按contact_id分组,因此浪费了您的“ bf.bundle_feedback_supporting”。 如果您需要反馈的数量,只需从该表中按每个联系人ID进行计数,然后删除其余的即可。 (同样,为了保持一致性,联接应具有“ ON”子句,而不是在WHERE子句中)

另外,对于您的支持反馈,数据类型和值还不清楚,因此我隐含为是或否,并根据支持的数量有一个SUM()。 因此,一个给定的联系人可能有100条记录,但只有37条支持。 这将为您提供一条记录,该记录分别具有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;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM