7
votes

Rejoindre des tables si la référence existe

J'ai eu une base de données PostgreSQL avec 4 tables:

Table A STROND> P>

-------------------------------------------------
| ID | ID_B | ID_C | ID_D | DATA (B) | DATA (C) |
-------------------------------------------------
| 1  |   1  | NULL | NULL |   123    |   NULL   |
-------------------------------------------------
| 2  | NULL |  1   | NULL |   NULL   |   789    |
-------------------------------------------------
| 3  |   2  |  2   | NULL |   456    |   102    |
-------------------------------------------------


4 commentaires

J'ai édité ma réponse et j'ai ajouté le résultat que j'attends.


Vous n'avez pas montré les contraintes FK. TABLE_A.ID_B ET TABLE_A.ID_C FKS aux tables B et C? (Il semble qu'ils sont, mais cela n'est pas mentionné dans la question)


Vous avez raison. Ils sont fks.


Dans ce cas, ma réponse est équivalente à la requête de votre question.


4 Réponses :


2
votes

Compte tenu de vos besoins, votre requête me semble bonne envers moi.

Une alternative serait d'utiliser des sélectionnées imbriquées dans la projection, mais en fonction de vos données, d'index et de contraintes, cela pourrait être plus lent, car les sélectionnements nichés entraînent généralement. Boucles imbriquées, alors que les jointures peuvent être effectuées sous forme de jointures de fusion ou de boucles imbriquées: xxx

si Postgres fait La cache de sous-requête scalaire (comme l'oracle fait), puis sélectionnée peut aider au cas où vous auriez beaucoup de répétitions de données dans table_a


0 commentaires

5
votes

Le où "table_a". "id_b" n'est pas nul ou "table_a". "id_c" n'est pas null; code> peut être remplacé par la clause correspondante sur les tables B et C: Où "TABLE_B". "ID" n'est pas NULL ou "TABLE_C". "ID" n'est pas null; code>. Cela fonctionnerait également si table_a.id_b et table_a.id_c ne sont pas FKS aux tables B et C. Sinon, une rangée de table_a avec {5, 5,5,5} récupérerait deux rangées NULL des tables B et C.

SELECT ta."ID" AS a_id
        , ta."ID_B" AS b_id
        , ta."ID_C" AS c_id
        , ta."ID_D" AS d_id
        , tb."DATA" AS bdata
        , tc."DATA" AS cdata
FROM "Table_a" ta
LEFT JOIN "Table_B" tb on ta."ID_B" = tb."ID"
LEFT JOIN "Table_C" tc on ta."ID_C" = tc."ID"
WHERE tb."ID" IS NOT NULL OR tc."ID" IS NOT NULL
        ;


2 commentaires

Mieux :-). En dehors de votre requête étant une meilleure solution en cas de contraintes clés étrangères manquantes, avez-vous des points de repère de performance pour les deux variantes? J'ai tendance à penser qu'avec des index mis sur la clé étrangère, la requête originale serait plus rapide (et plus lisible), à ​​moins que l'optimiseur puisse apporter la transformation nécessaire ...


Oui, il diffère de la requête de la QQ, sauf dans le cas où Ra.ID_B et TA.ID_C ont des contraintes FK aux tables B et C. Voir mon commentaire sur le OQ. Sinon: la sémantique sera différente, les plans seront différents, la performance sera différente. (Dans les cas simples / petits cas, deux jointures de hachage seront utilisées et la différence sera très petite)



0
votes

Généralement Spealking La voie recommandée est de le faire dans une requête seulement et de laisser la base de données faire autant que possible, surtout si vous ajoutez d'autres opérations telles que le tri (commander par) ou la pagination plus tard. (limite ... offset ...) plus tard. Nous avons fait des mesures et il n'ya aucun moyen de trier / paginer plus rapidement dans Java / Scala, si vous utilisez l'une des collections de niveau supérieur, telles que des listes, etc.

RDBMS traite très bien avec des déclarations simples complexes, mais ils ont des difficultés à manipuler de nombreuses petites requêtes. Par exemple, si vous interrogez le "un" et la "nombreuses relation" dans une requête, il sera plus rapide que cela dans les instructions de 1 + N Sélectionner.

Quant à la jointure extérieure, nous avons effectué des mesures, et il n'y a pas de pénalité de performance réelle par rapport aux jointures intérieures. Donc, si votre modèle de données et / ou votre requête nécessitent une jointure extérieure, faites-le simplement. Si c'était un problème de performance, vous pouvez l'accorder plus tard.

Quant à vos comparaisons NULL, il pourrait indiquer que votre modèle de données pourrait être optimisé, mais c'est juste une supposition. Les chances sont que vous pouvez améliorer la conception de sorte que NULL ne soit pas autorisée dans ces colonnes.


3 commentaires

Connectez votre dernier paragraphe: il est courant et parfaitement normal d'avoir des valeurs nulles dans de telles colonnes. Je ne vois pas comment cela indiquerait un problème.


@Erwin c'est ce que j'avais l'intention de décrire. Comme l'anglais n'est pas ma langue maternelle, que puis-je améliorer pour que cela soit clair?


Votre anglais semble juste bien. Je supprimerais le dernier paragraphe.



3
votes

Puisque vous avez des contraintes de clé étrangère en place, l'intégrité référentielle est garantie et la requête de votre Q est déjà la meilleure réponse .

également indexé sur TABLE_B.ID et table_c.id sont donnés.

si cas de correspondance dans table_a sont rares (Moins d'environ 5%, selon la rangée avec et la distribution de données) a partiel Index multi-colonnes aiderait les performances: xxx

dans PostgreSQL 9.2 Un index de couverture ( Scan d'index uniquement à Postgres Parlance) pourrait aider encore plus - auquel cas vous incluriez toutes les colonnes d'intérêt dans l'index (pas dans mon exemple). Dépend de plusieurs facteurs tels que la largeur de la rangée et la fréquence des mises à jour de votre table.


0 commentaires