phpbar.de logo

Mailinglisten-Archive

Re: Select-Alternative?
Archiv Mailingliste mysql-de

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Select-Alternative?



Hi Jens,


Jens Benecke wrote:
> ich muss eine relativ grosse Abfrage über drei Tabellen realisieren, ohne
> daß mir mein Provider wegen Ressourcen aufs Kreuz steigt. Gibt es zu
> folgendem Code eine Alternative, die _nicht_ erst eine komplette temporäre
> Tabelle mit allen möglichen Kombinationen anlegt und dann anfängt zu
> filtern?

Ja. Schon mal was von einem JOIN gehört :)) ? Steht auch im Manual,
sowohl im mySQL-Manual als auch in _jedem_ SQL-Manual, da es sich um die
grundlegende Eigenschaft von Datenbanken handelt, Tabellen in Abfragen
sinnvoll verknüpfen zu können.

Dazu ein bisschen Datenbanktheorie:
Ein SELECT * FROM A, B macht ein karthesisches Produkt dieser beiden
Tabellen, verknüpft also zu jeder Zeile in A alle Zeilen in B. Heraus
kommt eine Tabelle mit Count(A) * Count(B) Elementen, die erst danach
von einer eventuellen WHERE-Klausel wieder geleert wird.
Mit einem JOIN legst du fest, dass zu jedem Datensatz in A nur die
Zeilen aus B dazugenommen werden, bei denen eine bestimmte Spalte mit
einem bestimmten Feld des A-Datensatzes übereinstimmt.

> Diese Lösung kommt mir als ziemlicher Ressourcenfresser vor. Jedenfalls
> erzeugt sie mit BIG_TABLES eine Temporärdatei von ca. 1.5GB Grösse ...
> 
> ---------------------------------------------------------------------------
> SELECT h.id, h.stadt1, h.stadt2, h.stadt3, s.id, s.name, ss.id, ss.name,
> sss.id, sss.name from h, staedte as s, staedte as ss, staedte as sss
> WHERE (.......) AND s.id=h.stadt1 AND ss.id=h.stadt2 AND sss.id=h.stadt3
> ORDER BY {je nachdem s.name, ss.name oder sss.name} ;
> ---------------------------------------------------------------------------

Wie wäre es mit:
SELECT h.id, h.stadt1, h.stadt2, h.stadt3, s1.id, s1.name, s2.id,
s2.name, s3.id, s3.name FROM ((h INNER JOIN stadt AS s1 ON
h.stadt1=s1.id) INNER JOIN stadt AS s2 ON h.stadt2=s2.id) INNER JOIN
stadt AS s3 ON h.stadt3=s3.id WHERE (........) ORDER BY (....);

Bevor die WHERE-Klausel zur Anwendung kommt, enthält die temporäre
Tabelle jetzt genauso viele Datensätze wie h zuvor, denn der JOIN geht
jeweils auf das ID-Feld der Stadt-Tabelle (und das sollte ja nur einen
Datensatz ergeben), also ist PRO Zeile in A mit 1 * 1 * 1 = 1
Datensätzen zu rechnen.

Beachte, dass die INNER JOINs nur dann eine Zeile zurückliefern, wenn
h.stadt1 und h.stadt2 und h.stadt3 gültige IDs aus der Tabelle stadt
enthalten! Sollte in einer Zeile von h das Feld s3 einen Wert enthalten,
der nicht in stadt.id auftaucht, dann liefert die Abfrage für _diese_
Zeile von h genau 1 * 1 * 0 = 0 Datensätze zurück. Keine Angst, die
anderen Zeilen von h sind davon nicht betroffen, so dass die
resultierende Tabelle dann eben h-1 Datensätze enthält (oder eben
soviele weniger, bei denen der JOIN nicht geklappt hat)

Um diese Problematik zu umgehen, gibt es den LEFT JOIN, den du statt dem
INNER JOIN verwenden kannst. Im eben genannten Beispiel würde bei einem
LEFT JOIN die Werte von s3.id und s3.name auf NULL gesetzt, daher ergäbe
sich für diese Zeile in h wieder 1 x 1 x 1 = 1 Datensätze, und die
resultierende Tabelle hat wieder genau h Zeilen.

Alle Klarheiten soweit beseitigt? :)

Gruß JAn

---
*** Weitere Infos zur Mailingliste und MySQL unter www.4t2.com/mysql 


Home | Main Index | Thread Index

php::bar PHP Wiki   -   Listenarchive