Question

Ok, voici une question que je me présente en ce moment sur une table qui a 45.000 dossiers et 65Mo en taille ... et est sur le point de devenir de plus en plus (donc je dois penser à la performance future et ici ):

SELECT count(payment_id) as signup_count, sum(amount) as signup_amount
FROM payments p
WHERE tm_completed BETWEEN '2009-05-01' AND '2009-05-30'
AND completed > 0
AND tm_completed IS NOT NULL
AND member_id NOT IN (SELECT p2.member_id FROM payments p2 WHERE p2.completed=1 AND p2.tm_completed < '2009-05-01' AND p2.tm_completed IS NOT NULL GROUP BY p2.member_id)

Et comme vous pouvez ou ne pas imaginer - il étrangle le serveur MySQL à l'arrêt ...

Ce qu'il fait est - il tire simplement le nombre de nouveaux utilisateurs qui se sont inscrits, ont au moins un « terminé » le paiement, tm_completed n'est pas vide (car il est peuplé que pour les paiements réalisés) et (Embedded Select) ce membre n'a jamais eu de « terminé » le paiement avant - ce qui signifie qu'il est un nouveau membre (juste parce que le système ne refacture et ainsi de suite, ce qui est la seule façon de faire la différence en quelque sorte entre un membre existant qui vient de se refacturés et un nouveau membre qui se est facturé pour la première fois).

Maintenant, est-il possible possible d'optimiser cette requête à utiliser moins de ressources ou quelque chose, et d'arrêter de prendre mes ressources mysql à genoux ...?

Suis-je manque toute information pour clarifier cette plus loin? Faites-moi savoir ...

EDIT:

Voici les indices déjà sur la table:

PRIMAIRES 46757 payment_id

member_id INDEX 23378 member_id

payer_id INDEX 11689 payer_id

coupon_id INDEX 1 coupon_id

tm_added INDEX 46757 tm_added, product_id

tm_completed INDEX 46757 tm_completed, product_id

Était-ce utile?

La solution

Ce genre de sous-requêtes IN sont un peu lent dans MySQL. Je reformule comme ceci:

SELECT COUNT(1) AS signup_count, SUM(amount) AS signup_amount
FROM   payments p
WHERE  tm_completed BETWEEN '2009-05-01' AND '2009-05-30'
AND    completed > 0
AND    NOT EXISTS (
           SELECT member_id
           FROM   payments
           WHERE  member_id = p.member_id
           AND    completed = 1
           AND    tm_completed < '2009-05-01');

Le chèque « tm_completed IS NOT NULL » est pas nécessaire que cela est sous-entendu par votre état de BETWEEN.

Assurez-vous également que vous avez un index sur:

(tm_completed, completed)

Autres conseils

Je me suis amusée mettre ensemble cette solution qui ne nécessite pas une sous-requête:

SELECT count(p1.payment_id) as signup_count, 
       sum(p1.amount)       as signup_amount  

  FROM payments p1
       LEFT JOIN payments p2 
       ON p1.member_id = p2.member_id
   AND p2.completed = 1
   AND p2.tm_completed < date '2009-05-01'

 WHERE p1.completed > 0
   AND p1.tm_completed between date '2009-05-01' and date '2009-05-30'
   AND p2.member_id IS NULL;

Évitez d'utiliser IN avec une sous-requête; MySQL n'optimise pas ces bien (bien qu'il y ait des optimisations en attente de 5.4 et 6.0 en ce qui concerne ce (voir ici ) Réécriture cela comme une jointure va probablement vous obtenir un gain de performance.

SELECT count(payment_id) as signup_count, sum(amount) as signup_amount
FROM payments p
LEFT JOIN (SELECT p2.member_id
          FROM payments p2
          WHERE p2.completed=1
          AND p2.tm_completed < '2009-05-01'
          AND p2.tm_completed IS NOT NULL
          GROUP BY p2.member_id) foo
ON p.member_id = foo.member_id AND foo.member_id IS NULL
WHERE tm_completed BETWEEN '2009-05-01' AND '2009-05-30'
AND completed > 0
AND tm_completed IS NOT NULL

En second lieu, je dois voir votre schéma de la table; vous utilisez des index?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top