MySQL查询 - 帮助改进

时间:2013-04-02 08:42:33

标签: mysql performance query-optimization

我要执行此查询:

SELECT u1.firstname,
       u1.lastname,
       u1.totalcommission,
       u1.userid,
       count(DISTINCT u2.userid) AS level1,
       count(DISTINCT u3.userid) AS level2
FROM users AS u1
INNER JOIN users AS u2 ON u1.userid = u2.affiliate1
AND u2.signupdate BETWEEN '2011-01-01 00:00:00' AND '2013-04-02 23:59:59'
LEFT JOIN users AS u3 ON u1.userid = u3.affiliate2
WHERE u1.usertypeid != '1'
GROUP BY u1.userid
ORDER BY count(DISTINCT u2.userid) DESC

表的索引:

PRIMARY BTREE   Yes No  userid  41318   A   No  
email   BTREE   Yes No  email   41318   A   No  
affiliate1  BTREE   No  No  affiliate1  1967    A   Yes 
affiliate2  BTREE   No  No  affiliate2  258 A   Yes 
signupdate  BTREE   No  No  signupdate  41318   A   No

查询有效,但问题是它真的很慢(表用户有43k行,不多),由于计数(不同)函数需要大约10秒。有没有办法用表现更好的东西取而代之?

谢谢,

/卢卡

2 个答案:

答案 0 :(得分:0)

您已经按user_id进行分组,而不是将其计入订单。或者,您可以使用DESC with group by

对其进行简单的订购
SELECT
  u1.firstname,
  u1.lastname,
  u1.totalcommission,
  u1.userid,
  count( distinct u2.userid ) AS level1,
  count( distinct u3.userid ) AS level2
FROM users AS u1
  INNER JOIN users AS u2
    ON u1.userid = u2.affiliate1
  INNER JOIN users AS u3
    ON u1.userid = u3.affiliate2
WHERE u1.usertypeid != '1'
    and u2.signupdate between '2011-01-01 00:00:00'
    and '2013-04-02 23:59:59'
GROUP BY u1.userid DESC , u2.userid , u3.userid

答案 1 :(得分:0)

由于一些意想不到的笛卡尔结果,你可能会受到破坏。我会尝试以下方法。由于您的第一个内部联接基于affiliate1条目必须存在,我会预先聚合这些条目以获得每个联盟会员1条记录,其中联盟会员的ID加入到用户表中,并且只获取用户键入的那些!='1'。这基本上为你创造了你的计数DISTINCT。然后,加入用户表以获取该联盟会员的用户信息。然后,做一个类似的左连接,但对于第二个联盟(如果存在任何...也基于联盟会员的用户类型!='1')。

现在,每张桌子的MAX比率为1:1,应该非常快。

SELECT 
      u1.firstname,
      u1.lastname,
      u1.totalcommission,
      u1.userid,
      PreAggUA1.AffiliateUsers as Level1,
      PreAggUA2.AffiliateUsers as Level2
   FROM 
      ( select 
              ua1.affiliate1,
              count(*)  as AffiliateUsers
           from users ua1
              join users ua1b
                  on ua1.affiliate1 = ua1b.userid
                 and ua1b.userTypeID != '1'
              group by
                 ua1.affiliate1 ) as PreAggUA1

         JOIN Users u1
            on PreAggUA1.Affiliate1 = u1.UserID

         LEFT JOIN ( select 
                           ua2.affiliate2,
                           count(*)  as AffiliateUsers
                        from 
                           users ua2
                              join users ua2b
                                 on ua2.affiliate2 = ua2b.userid
                                and ua2b.userTypeID != '1'
                         group by
                            ua2.affiliate2 ) as PreAggUA2
            on PreAggUA1.Affiliate1 = PreAggUA2.Affiliate2
   ORDER BY 
      PreAggUA1.AffiliateUsers DESC