mySQL-JOIN: Entweder nur einmal, oder keinmal.
split.s
- datenbank
0 Vinzenz Mai0 Thomas0 Vinzenz Mai0 Thomas
0 Tom
Habe eine Datenbank mit Benutzern.
Dazu gibts zwei Tabellen in die ich gerne joinen würde.
Das sieht etwa so aus:
SELECT
users.id
FROM
users LEFT OUTER JOIN tab2 ON tab2.userId = users.id
LEFT OUTER JOIN tab3 ON tab3.userId = users.id
WHERE
... ?
Mein Problem: Ich bin nicht gut genug in Joins. Gesucht ist folgendes Konstrukt:
Der Benutzer darf nur in einer der beiden gejointen Tabellen vorkommen, aber nicht in beiden gleichzeitig! Natürlich kann er auch in keiner von beiden vorkommen.
Wie würde man sowas formulieren?
LG
Hallo,
Dazu gibts zwei Tabellen in die ich gerne joinen würde.
Ilja würde sagen: Joins sind böse ;-)
Mein Problem: Ich bin nicht gut genug in Joins. Gesucht ist folgendes Konstrukt:
Der Benutzer darf nur in einer der beiden gejointen Tabellen vorkommen, aber nicht in beiden gleichzeitig! Natürlich kann er auch in keiner von beiden vorkommen.
geht mit Joins, ist aber unschön.
Wie würde man sowas formulieren?
mit zwei Subselects:
Gib mir
die Benutzer
aus der
Tabelle 1
wobei nur die interessieren
die nicht in der Liste der Benutzer aus Tabelle 2 enthalten sind
oder
die nicht in der Liste der Benutzer aus Tabelle 3 enthalten sind
(kannst Du natürlich auch umgekehrt mit einer und-Verknüpfung formulieren).
Die Lösung mit Joins wäre bei weitem nicht so verständlich wie mein Pseudocode, der sich praktisch 1:1 in SQL umsetzen lässt.
Freundliche Grüße
Vinzenz
Hallo,
Ilja würde sagen: Joins sind böse ;-)
Hätte Ilja auch Gründe?
Gruß,
Thomas
Hallo Thomas,
Ilja würde sagen: Joins sind böse ;-)
Hätte Ilja auch Gründe?
Klar, eine Auswahl:
</archiv/2010/10/t201415/#m1358742>,
</archiv/2010/4/t197346/#m1323623>,
</archiv/2010/5/t197951/#m1328627>
Freundliche Grüße
Vinzenz
Hallo Vinzenz,
Klar, eine Auswahl:
</archiv/2010/10/t201415/#m1358742>,
</archiv/2010/4/t197346/#m1323623>,
</archiv/2010/5/t197951/#m1328627>
Danke.
Aber gibt es dafür auch irgendwie tieferen Gründe, als dass man einen Fehler dabei machen könnte (so liest es sich für mich zumindest)?
Ich konnte nur "und zweitens könnte die abfrage ohne den JOIN schneller sein." (Quelle) finden. Das ist doch recht vage formuliert und hört sich ehr nach einer Vermutung an.
Gibt es da irgendwelche Belege/Benchmarks/etc?
Google brachte leider nur eine spärliche Auswahl an Ergebnissen.
Gruß,
Thomas
Hallo Thomas,
</archiv/2010/10/t201415/#m1358742>,
</archiv/2010/4/t197346/#m1323623>,
</archiv/2010/5/t197951/#m1328627>
Aber gibt es dafür auch irgendwie tieferen Gründe, als dass man einen Fehler dabei machen könnte (so liest es sich für mich zumindest)?
dass Joins das falsche Werkzeug für eine Aufgabe sein können :-)
Wie war's: "Wenn man bloß einen Hammer hat, sieht alles aus wie ein Nagel."
Wenn's *keinen* relevanten Performanceunterschied gibt, bevorzuge ich die leichter verständliche Variante gegenüber einer komplexen Lösung, die allein durch ihre Komplexität fehlerträchtiger ist. Ist's performancerelevant, muss man eh' alle Register der Optimierung ziehen und messen, messen und nochmals messen.
Die Subselect-Variante für die Aufgabe hier im Thread ist mit Sicherheit lesbarer, verständlicher und damit wartbarer und weniger fehlerträchtig als eine, die auf Subselects deswegen verzichten und mit Joins auskommen muss, weil die eingesetzte MySQL-Version die seit Jahren tote 4.0.x (oder schlimmer) ist, die noch keine Subselects unterstützt. Für den Einsatz einer solchen Leiche in einer Produktivumgebung habe ich sehr wenig Verständnis.
Freundliche Grüße
Vinzenz
Hallo Vinzenz,
Ok, Wartbarkeit ist tatsächlich ein Grund, wobei so ein JOIN ja oft einfach benutzt wird um eine _simple_ Verknüpfung darzustellen (z.B. von userID auf Namen schließen).
Das sind in der Regel so aus:
JOIN userTbl ON userTbl.id = foo.userId
Jeder mit SQL-Grundkentnissen sollte die Verknüpfung erkennen und verstehen können - denke ich.
Wenn's *keinen* relevanten Performanceunterschied gibt, bevorzuge ich die leichter verständliche Variante gegenüber einer komplexen Lösung, die allein durch ihre Komplexität fehlerträchtiger ist. Ist's performancerelevant, muss man eh' alle Register der Optimierung ziehen und messen, messen und nochmals messen.
Und was sagt deine Erfahrung? Ich würde mal tippen gerade bei komplexen und vielen JOINs kann ein gutes DBMS optimieren, aber ich muss gestehen ich habe noch nie nachgemessen.
Gruß,
Thomas
moin,
Ok, Wartbarkeit ist tatsächlich ein Grund, wobei so ein JOIN ja oft einfach benutzt wird um eine _simple_ Verknüpfung darzustellen (z.B. von userID auf Namen schließen).
die wartbarkeit ist ein aspekt, die performance ein anderer, aber beides ist nicht der hauptgrund, warum joins "böse" sind. es geht darum, eine gute methode anzuwenden, wie man ein sql statement aufbaut. das ist eine grundsätzliche methodik, die man sich aneignen sollte, weil man nach meiner erfahrung damit wesentlich weniger fehler macht. und genau bei dem weg, den du hier anführst, kommen die besagten probleme, indem man schnell noch mal ein attribut in der projektion mit anzeigen will. für mich ist der richtige weg aber genau entgegen gesetzt, sprich man läßt die projektion erst einmal komplett aussen vor, wichtig ist zuvor die richtige selektion, sprich die richtige datenbasis in der ergebnismenge zu finden. hilfreich dafür wäre erst mal nur die selektion zu erstellen und in der projektion ein COUNT(*) ausgeben zu lassen. und erst wenn die selektion steht, dann sollte man sich gedanken über die projektion machen. und selbst dann bevorzuge ich unterabfragen in der projektion als joins.
natürlich machen auch joins an der richtigen stelle sinn, sehr viel sogar, zum beispiel wenn ich eben genau diese mögliche vervielfachung der datensätze durch jons brauche, als genau das die gewünchte datenbasis der ergebnistabelle darstellt. und natürlich kann ich auch mal schnell joins für eine ad hoc abfrage bilden, wenn die anzahl der datensätze nicht relevant ist, sondern ich mir nur schnell einen überblick verschaffen will. oder aber mir sind die beziehungen der tabellen untereinander bewußt. das ist dann aber ein ganz expliziter und bewußter vorgang, wo ich mir bei jedem join (und wirklich jedem) gedanken über die art der beziehung mache und wie es sich auf die ergebnistabelle auswirkt.
JOIN userTbl ON userTbl.id = foo.userId
Jeder mit SQL-Grundkentnissen sollte die Verknüpfung erkennen und verstehen können - denke ich.
lesbarkeit bedeutet nicht, dass man weiß, wie ein JOIN gebildet wird, sondern wie schnell ich eine abfrage verstehen kann, wenn ich sie zum beispiel zum ersten mal lese oder seit langer zeit mal wieder. natürlich kann man oftmals einen join durch geschickte bedinungen auch so aufbauen, dass man zum gleichen ergebnis kommen würde, als wenn man unterabfragen benutzt. aber in aller regel ließt sich der sinn hinter der abfrage schwieriger, der fachliche sinn, nicht das verständnis wie ein JOIN aufgebaut ist. wenn ich nur eine tabelle in der FROM klausel habe und alles weitere mit unerabfragen abfackel, dann weiß ich auf den ersten blick viel schneller, um welche daten es geht. habe ich mehrere tabellen dort durch JOINS im verbund, dann muss ich mir erst mal gedanken machen, um welche entität jetzt eine aussage gemacht werden soll oder ist es wichtig, dass es um zwei entitäten geht, ist der join nur vorhanden, um in die projektion zugehen oder die selektion weiter einzugrenzen, etc.
Und was sagt deine Erfahrung? Ich würde mal tippen gerade bei komplexen und vielen JOINs kann ein gutes DBMS optimieren, aber ich muss gestehen ich habe noch nie nachgemessen.
performace ist so eine sache bei datenbanken. es gibt ein grundsatz, es kommt oftmals anders als man denkt. natürlich zählen auch die erfahrungswerte dabei und es kommt oftmals auch hin, aber wenn wirklich tuning bedarf besteht, dann muss man eben messen und nochmals messen, wie Vinzenz schon richtigerweise erwähnte. aber aus meiner erfahrung heraus, sind die unterabfragen besser, als joins, erst recht wenn dann noch OUTER JOINS ins spiel kommen.
also noch mal zusammengefasst, warum ich zu dem motto komme, dass JOINS "böse" sind.
und alleine der erste grund ist schon gewichtig genug.
Ilja
Hello,
Der Benutzer darf nur in einer der beiden gejointen Tabellen vorkommen, aber nicht in beiden gleichzeitig! Natürlich kann er auch in keiner von beiden vorkommen.
Und soll er dann, wenn er noch nirgendwo vorkommt, in eine der beiden Tabellen eingetragen werden?
Dann hasdt Du nämlich das nächste Problem!
Ich spiel mal wieder "Mister TOCTTOU" und verweise Dich auf diesen Thread:
http://forum.de.selfhtml.org/archiv/2010/11/t201483/#m1359235
Da ging es zwar um Termine, aber vielleicht macht es das Problem deutlich.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg