MySQL,左连接选择和创建索引

时间:2018-07-11 10:47:19

标签: mysql sql

我的SQL查询缓慢(所有数据均正常工作)。我的问题是查询的工作量超过〜2sek。

SELECT CONCAT(YEAR(FROM_UNIXTIME(pixel.adddate)), '/', MONTHNAME(FROM_UNIXTIME(pixel.adddate))) AS period,
       COUNT(pixel.id) AS clicks,
       COUNT(postbacktracker.id) AS conversions,
       CONCAT(HOUR(FROM_UNIXTIME(TRUNCATE(pixel.adddate / 3600, 0) * 3600)), ' - ', (HOUR(FROM_UNIXTIME(TRUNCATE(pixel.adddate / 3600, 0) * 3600)) + 1)) AS hour,
       DAYNAME(FROM_UNIXTIME(TRUNCATE(pixel.adddate / 86400, 0) * 86400)) AS DAY,
       CONCAT(YEAR(FROM_UNIXTIME(pixel.adddate)), '/', WEEK(FROM_UNIXTIME(pixel.adddate))) AS week,
       MONTHNAME(FROM_UNIXTIME(pixel.adddate)) AS MONTH,
       YEAR(FROM_UNIXTIME(pixel.adddate)) AS YEAR,
       FROM_UNIXTIME(MIN(pixel.adddate)) AS min_date,
       FROM_UNIXTIME(MAX(pixel.adddate+1)) AS max_date,
       pixel.adddate AS adddate,
       products.id AS OfferID,
       products.name AS name,
       campaign.id AS id,
       campaign.name AS campaign_name,
       pixel.transaction_id AS TransactionID,
       pixel.url AS url,
       campaign.mkey AS mkey,
       team_users.first_name AS first_name,
       team_users.last_name AS lastname,
       team_users.company AS company,
       team_users.email AS email,
       team_users.hasoffersid AS affiliateid,
       COUNT(userdata.id) AS user_exists,
       SUM(userdata.orders) AS total_operations,
       COUNT(CASE
                 WHEN userdata.orders != 0 THEN 1
             END) AS total_sales,
       COUNT(CASE
                 WHEN userdata.orders = 1 THEN 1
             END) AS sales_without_upsells,
       COUNT(CASE
                 WHEN userdata.orders > 1 THEN 1
             END) AS sales_with_upsells,
       SUM(userdata.pvalue_sum) AS total_sales_sum,
       SUM(CASE
               WHEN userdata.orders = 1 THEN userdata.pvalue_sum
           END) AS sales_wo_up,
       SUM(CASE
               WHEN userdata.orders > 1 THEN userdata.pvalue_sum
           END) AS sales_w_up,
       (SUM(CASE
                WHEN userdata.orders = 1 THEN userdata.pvalue_sum
            END)/COUNT(CASE
                           WHEN userdata.orders = 1 THEN 1
                       END)) AS AOVCheckout,
       (SUM(CASE
                WHEN userdata.orders > 1 THEN userdata.pvalue_sum
            END)/COUNT(CASE
                           WHEN userdata.orders > 1 THEN 1
                       END)) AS AOVinclupsells,
       (((SUM(CASE
                  WHEN userdata.orders = 1 THEN userdata.pvalue_sum
              END)/COUNT(CASE
                             WHEN userdata.orders = 1 THEN 1
                         END)) + (SUM(CASE
                                          WHEN userdata.orders > 1 THEN userdata.pvalue_sum
                                      END)/COUNT(CASE
                                                     WHEN userdata.orders > 1 THEN 1
                                                 END)))/2) AS AOVall,
       COUNT(CASE
                 WHEN userdata.orders = 0 THEN 1
             END) AS presale,
       COUNT(CASE
                 WHEN userdata.orders != 0 THEN 1
             END) AS sale,
       COUNT(pixel_count.id) AS PARTIAL,
       (COUNT(pixel.id) - COUNT(pixel_count.id)) AS sales,
       SUM(userdata.sendtry) AS Declines,
       ((COUNT(postbacktracker.id)/COUNT(pixel.id))*100) AS Cr,
       SUM(postbacktracker.payout) AS Payout,
       SUM(postbacktracker.payout)/COUNT(pixel.id) AS Epc
FROM campaign
LEFT JOIN pixel ON campaign.mkey = pixel.defa
LEFT JOIN products ON products.id = pixel.offer_id
LEFT JOIN team_users ON pixel.aff_id = team_users.hasoffersid
LEFT JOIN
  (SELECT id,
          userkey,
          payout
   FROM postbacktracker
   GROUP BY userkey) postbacktracker ON pixel.transaction_id = postbacktracker.userkey
LEFT JOIN
  (SELECT pixel.id,
          COUNT(postbacktracker.id) AS conversions
   FROM pixel
   LEFT JOIN postbacktracker ON pixel.transaction_id = postbacktracker.userkey
   GROUP BY pixel.id
   HAVING conversions = 0) pixel_count ON pixel_count.id = pixel.id
LEFT JOIN
  (SELECT userdata.id,
          userdata.ukey,
          userdata.sendtry,
          COUNT(produktorder.id) AS orders,
          SUM(produktorder.pvalue) AS pvalue_sum
   FROM userdata
   LEFT JOIN produktorder ON produktorder.nekp1stv1r = userdata.nekp1stv1r
   GROUP BY userdata.id) userdata ON pixel.transaction_id = userdata.ukey
WHERE pixel.adddate >= 1527853697
  AND pixel.adddate < 1531223297
GROUP BY campaign.id,
         period
ORDER BY campaign.id,
         pixel.adddate,
         hour ;

问题出在这部分查询中(没有这个左联接查询是在0.0035秒内完成的。):

LEFT JOIN
  (SELECT pixel.id,
          COUNT(postbacktracker.id) AS conversions
   FROM pixel
   LEFT JOIN postbacktracker ON pixel.transaction_id = postbacktracker.userkey
   GROUP BY pixel.id
   HAVING conversions = 0) pixel_count ON pixel_count.id = pixel.id

此查询的正确构造的索引应如何显示?

这是解释结果:

1   PRIMARY pixel       ALL index_defa,index_adddate                231 99.13   Using where; Using temporary; Using filesort    
1   PRIMARY campaign        ref index_mkey  index_mkey  902 thanatos.pixel.defa 1   100.00  Using index 
1   PRIMARY products        eq_ref  PRIMARY PRIMARY 4   thanatos.pixel.offer_id 1   100.00      
1   PRIMARY team_users      ref index_hasoffersid   index_hasoffersid   4   thanatos.pixel.aff_id   1   100.00  Using index 
1   PRIMARY <derived2>      ref <auto_key0> <auto_key0> 902 thanatos.pixel.transaction_id   2   100.00      
1   PRIMARY <derived3>      ref <auto_key0> <auto_key0> 4   thanatos.pixel.id   10  100.00      
3   DERIVED pixel       ALL PRIMARY             231 100.00  Using temporary; Using filesort 
3   DERIVED postbacktracker     ref index_userkey   index_userkey   902 thanatos.pixel.transaction_id   2   100.00      
2   DERIVED postbacktracker     ALL index_userkey               19  100.00  Using temporary; Using filesort 

感谢帮助。

3 个答案:

答案 0 :(得分:0)

那是一个非常奇怪的构造。我会简单地删除它。

为什么?

  • 这是left join,因此它不会过滤掉任何行。
  • 子查询conversions中的一个值未在查询中的任何地方使用。

因此,join似乎没有做任何有用的事情,您可以删除它。 (它有可能乘以行数,但是我猜这没有用。)

答案 1 :(得分:0)

首先,您不应该使用case循环这样的sql查询。请编写一个函数并调用它。您将看到,您的查询将比平常更快地返回。您的问题主要基于案例循环。因为您已经互相加入了很多表。您知道如何编写sql函数吗?

答案 2 :(得分:-1)

可以请您试试吗?这可能会让您烦恼。

SELECT pixel.id,
          COUNT(postbacktracker.id) AS conversions INTO #pixel_count
   FROM pixel
   LEFT JOIN postbacktracker ON pixel.transaction_id = postbacktracker.userkey
   GROUP BY pixel.id
   HAVING conversions = 0


SELECT CONCAT(YEAR(FROM_UNIXTIME(pixel.adddate)), '/', MONTHNAME(FROM_UNIXTIME(pixel.adddate))) AS period,
       CONCAT(HOUR(FROM_UNIXTIME(TRUNCATE(pixel.adddate / 3600, 0) * 3600)), ' - ', (HOUR(FROM_UNIXTIME(TRUNCATE(pixel.adddate / 3600, 0) * 3600)) + 1)) AS hour,
       pixel.adddate AS adddate,
       products.id AS OfferID,
       products.name AS name,
       campaign.id AS id,
       campaign.mkey AS mkey
FROM campaign
LEFT JOIN pixel ON campaign.mkey = pixel.defa
AND pixel.adddate >= 1527832290
AND pixel.adddate < 1531201890
LEFT JOIN #pixel_count AS pixel_count ON pixel_count.id = pixel.id
LEFT JOIN products ON products.id = pixel.offer_id
LEFT JOIN team_users ON pixel.aff_id = team_users.hasoffersid
LEFT JOIN
  (SELECT id,
          userkey,
          payout
   FROM postbacktracker
   GROUP BY userkey) postbacktracker ON pixel.transaction_id = postbacktracker.userkey

GROUP BY campaign.id,
         period
ORDER BY campaign.id,
         pixel.adddate,
         hour ;