web-dev-qa-db-fra.com

Utilisation de la jointure interne DISTINCT dans SQL

J'ai trois tables, A, B, C, où A est plusieurs à un B, et B est plusieurs à un C. Je voudrais une liste de tous les C de A.

Mes tables ressemblent à ceci: A [id, valeurA, lookupB], B [id, valeurB, lookupC], C [id, valeurC]. J'ai écrit une requête avec deux SELECTs imbriqués, mais je me demande s'il est possible de faire INNER JOIN avec DISTINCT d'une manière ou d'une autre.

SELECT valueC
FROM C
INNER JOIN
(
    SELECT DISTINCT lookupC
    FROM B INNER JOIN
    (
        SELECT DISTINCT lookupB
        FROM A
    ) 
    A2 ON B.id = A2.lookupB
) 
B2 ON C.id = B2.lookupC

EDIT: Les tables sont assez grandes, A correspond à 500k lignes, B à 10k lignes et C à 100 lignes. Il existe donc de nombreuses informations inutiles si je fais une jointure interne de base et que j'utilise DISTINCT à la fin, comme ceci:

SELECT DISTINCT valueC
FROM 
C INNER JOIN B on C.id = B.lookupB
INNER JOIN A on B.id = A.lookupB

C'est très, très lent (les magnitudes sont parfois plus lentes que le SELECT imbriqué ci-dessus.

34
Mats Fredriksson

J'ai fait un test sur MS SQL 2005 en utilisant les tables suivantes: A 400K lignes, B 26K lignes et C 450 lignes.

Le plan de requête estimé indiquait que la jointure interne de base serait 3 fois plus lente que les sous-requêtes imbriquées. Toutefois, lors de l'exécution de la requête, la jointure interne de base était deux fois plus rapide que les requêtes imbriquées. La jointure interne de base prenait 297 ms matériel de serveur minimal.

Quelle base de données utilisez-vous et quelle heure voyez-vous? Je pense que si les performances sont médiocres, il s’agit probablement d’un problème d’index.

15
Darrel Miller

Je crois que vos relations 1: m devraient déjà créer implicitement des jointures DISTINCT.

Mais, si votre objectif est uniquement de C dans chaque A, il serait peut-être plus facile d'utiliser simplement DISTINCT sur la requête la plus externe.

SELECT DISTINCT a.valueA, c.valueC
FROM C
    INNER JOIN B ON B.lookupC = C.id
    INNER JOIN A ON A.lookupB = B.id
ORDER BY a.valueA, c.valueC
9
SELECT DISTINCT C.valueC 
FROM C 
  LEFT JOIN B ON C.id = B.lookupC
  LEFT JOIN A ON B.id = A.lookupB
WHERE C.id IS NOT NULL

Je ne vois pas de bonne raison pour laquelle vous souhaitez limiter les résultats de A et B, car vous souhaitez obtenir une liste de tous les C référencés par A. J'ai effectué une analyse distincte sur C.valueC car je vous ai deviné. voulait une liste unique de C.


EDIT : Je suis d'accord avec votre argument. Même si votre solution semble un peu imbriquée, elle semble être le moyen le plus rapide et le plus simple d'utiliser votre connaissance des données et de réduire le nombre de résultats.

Il n'y a pas de construction de jointure distincte que vous pourriez utiliser, alors restez avec ce que vous avez déjà :)

3
VVS

C'est ce que tu veux dire?

SELECT DISTINCT C.valueC
FROM 
C
INNER JOIN B ON C.id = B.lookupC
INNER JOIN A ON B.id = A.lookupB
0
kristian