2012-01-03 4 views
2

Je voudrais de l'aide pour la jointure suivante. J'ai une table (avec environ 20 millions de lignes) qui se compose de:Joindre une table sur elle-même - performance

MemberId (clé primaire) | Id (clé primaire) | TransactionDate | Solde

Je voudrais obtenir la dernière Balance pour tous les clients en une seule requête. Je sais que je pourrais faire quelque chose comme ça (je l'ai juste écrit de ma mémoire). Mais c'est terriblement lent.

SELECT * 
FROM money 
WHERE money.Id = (SELECT MAX(Id) 
        FROM money AS m 
        WHERE m.MemberId = money.MemberId) 

Existe-t-il d'autres options (plus rapides/plus intelligentes)?

+0

Pour être sûr, la clé primaire est composite, et la première colonne est MemberId? – Benoit

+0

Umbrella a une bonne réponse, mais je serais vraiment intéressé de savoir comment MySQL gère l'opérateur 'IN' (remplacez le premier' = '), si cela ne vous dérange pas. –

+0

@Benoit Oui la clé primaire est composite et la première colonne est MemberId (c'est une table MyIsam) – PKK

Répondre

5

Dans tous les tutoriels d'optimisation et screencasts que j'ai endurées à travers, toujours les jointures sont favorisés par rapport aux sous-requêtes. Lors de l'utilisation d'une sous-requête, la sous-requête est exécutée pour chaque comparaison, où comme avec une jointure une seule fois.

SELECT * 
FROM money m 
INNER JOIN (
    SELECT memberId, MAX(id) AS maxid 
    FROM money 
    GROUP BY memberId 
) mmax ON mmax.maxid = m.id AND mmax.memberId = m.memberId 
+0

Vraiment belle solution. C'était beaucoup plus rapide que la requête que j'ai utilisée – PKK

0

Autre option consiste à rechercher des valeurs NULL dans une jointure gauche:

SELECT m1.* 
    FROM money m1 
    LEFT JOIN money m2 ON m2.memberId = m1.memberId AND m2.id > m1.id 
WHERE m2.memberId IS NULL 

Mais bien sûr Umbrella's answer est mieux.

2

L'association n'est pas la meilleure solution. Pensez à utiliser une clause GROUP BY pour passer au crible la dernière transaction pour chaque membre, comme ceci:

SELECT MemberID, MAX (Id), TransactionDate, SOLDE DE GROUPE argent PAR MemberID

MISE À JOUR

comme l'a souligné PKK, l'équilibre sera choisi au hasard. Il semblerait que vous deviez effectuer une sorte de jointure après tout. Considérez cette option:

SELECT MemberId, Id, TransactionDate, Balance FROM money WHERE Id IN (
    SELECT MAX(Id) FROM money GROUP BY MemberId 
) 
+0

Bien sûr ... comment ne pas y penser ... – Benoit

+0

Modifié pour obtenir l'ID Max au lieu de Date – Umbrella

+0

TransactionDate et Balance seront choisis aléatoirement. Non selon le MAX (Id) – PKK

Questions connexes