2013-04-02 5 views
0

Je cette requête à effectuer:requête MySQL - aide pour améliorer

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 

Les index de la table:

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 

La requête fonctionne, mais le problème est qu'il est vraiment lent (le les utilisateurs de table ont 43k lignes, pas plus), cela prend environ 10sec, en raison des fonctions de comptage (distinctes). Y a-t-il un moyen de le remplacer par quelque chose de plus performant?

Merci,

/Luca

+0

et vous affichez les structures de toutes les tables? Quels sont les index sur la table? –

+0

Pourriez-vous ajouter "DESC" avant la requête et ajouter la sortie de cette requête à votre question? Cette requête vous montrera où et quelles clés sont utilisées. –

Répondre

0

Vous êtes probablement obturé en raison de résultats cartésiens inattendus. Je voudrais essayer ce qui suit. Puisque votre première jointure interne est basée sur les entrées affiliate1, je les pré-agréger pour obtenir 1 enregistrement par affilié où l'ID de l'affilié rejoint la table des utilisateurs et ne reçoit que ceux où type d'utilisateur! = '1'. Cela crée essentiellement votre compte DISTINCT pour vous. Ensuite, joignez-vous à la table des utilisateurs pour obtenir les informations sur l'utilisateur pour cet affilié. Ensuite, faites une jointure à gauche similaire, mais pour le 2ème affilié (s'il en existe un ... aussi basé sur le type d'utilisateur de l'affilié! = '1').

Maintenant, vous aurez au MAX un ratio de 1: 1 par table et devrait être très rapide.

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 
+0

fonctionne comme un charme! Merci beaucoup! –

0

Vous regroupez déjà par user_id et que le comptage à l'ordre. Vous pouvez également le commander simplement en utilisant DESC avec le groupe par

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 
+0

Merci ... malheureusement, cette requête prend encore 10 secondes –

+0

@ Lucone83 J'ai mis à jour la requête. réessayer! –

+0

Merci ... de cette façon vous éliminez au moins un compte distinct, et c'est bien, mais c'est quand même lent (9 sec). Connaissez-vous un moyen de remplacer l'autre compte (distinct)? –