SQL mySQL-DB-Abfrage mehrerer Tabellen ohne verschachtelte Abfragen

  • Ersteller Ersteller Mr. Snoot
  • Erstellt am Erstellt am
M

Mr. Snoot

Gast
Hio,

da ich gerade dabei bin mein komplettes PHP-Scrapt (;)) umzubauen, wollte ich jetzt noch schauen, wie ich mehrere DB-Abfragen aus unterschiedlichen Tabellen zusammenfassen kann. Bis dato ist das leider alles immer in verschachtelten DB-Abfragen geschehen, was natürlich vermieden werden sollte.

Ich habe also drei Tabellen, die über IDs miteinander in Beziehung stehen:
tabellen.png

Jetzt möchte ich bspw. ein Inhaltsverzeichnis ausgeben:
toc.png


Wenn ich das so mache ...
PHP:
<?php

$sql = "SELECT
  b.bereich, k.kapitel, a.absatz
FROM
  bereich AS b, kapitel AS k, absatz AS a
WHERE
  b.id_bereich = k.id_bereich AND k.id_kapitel = a.id_kapitel
ORDER BY
  b.id_bereich, k.id_kapitel, a.id_absatz";

$sql = mysql_query($sql);
while($row = mysql_fetch_object($sql))
{
  echo $row->bereich;
  echo ": ";
  echo $row->kapitel;
  echo ": ";
  echo $row->absatz;
  echo "<br>";
}

?>

... erhalte ich logischerweise sowas:
tocf.png


Lässt sich das, was ich vorhabe überhaupt ohne verschachtelte Abfragen lösen? Es ist ja klar, dass ich auf obigem Weg bereich und kapitel bei jedem Durchlauf auch immer mit ausgebe.
 
Mir fallen da spontan 3 Möglichkeiten ein:
  1. du speicherst dir jedesmal, welches Element du zuletzt ausgegeben hast. Wenn du (grundlagen, dotieren, p-leiter) Ausgibst, kannst du also nachschlagen, dass das letzte Element die gleichen Kategorien hatte und dementsprechend die Kategorien weglassen (dein Beispiel)
  2. du liest dich mal in "Nested Sets" rein, das sind Bäume abgebildet auf SQL, Gedanken bei der Ausgabe musst du dir aber noch immer machen.
  3. du schreibst erst alle Ergebnisse in ein Array und formatierst dieses Array dann um, dass es die gleiche Semantik wie deine Ausgabe hat (verschachtelte Mengen). Ist im Prinzip wie meine 1. Lösung nur, dass du hier die Daten für die Ausgabe vorformatierst und es nicht erst in der Ausgabe machst.

Eines solltest du dir auf jedenfall merken:
Querys in Schleifen sind evil! Wenn du dies machst, musst du sehr gute Gründe dafür haben!
 
Zuletzt bearbeitet:
ice-breaker schrieb:
Querys in Schleifen sind evil! Wenn du dies machst, musst du sehr gute Gründe dafür haben!
Gründe? Scheinbar ist das die praktikabelste Lösung ;)

Wenn ich mir deine anderen Möglichkeiten anschaue, sind mir diese alle wesentlich unsympatischer.

Zäumen wir das Pferd mal von hinten auf: wieso genau sollte man Abfragen in Schleifen unterlassen? Es liefert genau das, was ich will und es gibt für ähnliche Abfragen doch 1000 Beispiele, wo dies am besten funktioniert.
 
Queries in Schleifen skalieren sehr schlecht. Das kannst du machen wenn du eine bestimmte kleine Anzahl an Iterationen machst, aber nicht erst aus der Datenbank auslesen und dann für jede Zeile eine neue Einzelabfrage in der Datenbank. Das Ergebnis ist ein sehr ineffizientes Programm. Der Join innerhalb einer Datenbank ist algorithmisch erheblich schneller als eine Schleife (mind. O(n*m), durch Locking und Queryoverhead fällt das aber noch deutlich mehr ins Gewicht)! Wenn du nur eine ausreichend große Zahl an Iterationen machst bricht die Performance ganz empfindlich ein.
 
Zuletzt bearbeitet:
Wegen der Performance. Eine Query ist halt im Normalfall immer schneller als n Queries.

Edit: What he said :D
 
Mr. Snoot schrieb:
Gründe? Scheinbar ist das die praktikabelste Lösung ;)
nicht unbedingt, das lässt sich auch leicht, wieder gut nutzen:
PHP:
$results = $db->fetchAll('...');
$navigation = App_Array::group($results, 'bereich', 'kapitel');
und voila, hast du in einem Array direkt die Daten wunderbar verschachtelt, dass du sie in verschachtelten Schleifen ausgeben kannst.
Und nein, ich darf den Source der Methode leider nicht herausgeben.


Wenn ich mir deine anderen Möglichkeiten anschaue, sind mir diese alle wesentlich unsympatischer.[/QUOTE]
es ist natürlich die simpelste zum umsetzen. aber gleichzeitig auch die effizientes.
Meiner Meinung nach bewegen wir uns hier auf dem Grad zwischen Frickelei und Programmierung.


Mr. Snoot schrieb:
Zäumen wir das Pferd mal von hinten auf: wieso genau sollte man Abfragen in Schleifen unterlassen? Es liefert genau das, was ich will und es gibt für ähnliche Abfragen doch 1000 Beispiele, wo dies am besten funktioniert.

weil jede Abfrage Zeit kostet?
Ob ich eine Anfrage mit 1ms stelle oder es dann 20 sind ist schon ein erheblicher Zeitunterschied.
Und wie man sieht, führt es auch real zu Problemen.


IceMatrix schrieb:
Der Join innerhalb einer Datenbank ist algorithmisch erheblich schneller als eine Schleife (mind. O(n*m), durch Locking und Queryoverhead fällt das aber noch deutlich mehr ins Gewicht)! Wenn du nur eine ausreichend große Zahl an Iterationen machst bricht die Performance ganz empfindlich ein.
der Nested-Loop-Join in MySQL hat auch eine Komplexität von O(n*m) ;)
Aber natürlich entfallen bei einem Query da die vielen TCP-Kommunikationen, Queryparsing usw.
 
Wobei ich mal davon ausgehe, dass das bei mir kaum ins Gewicht fallen dürfte, oder?

Die Tabellen haben 8 (bereich), 37 (kapitel) und 118 (absätze) Zeilen; das wird sich zukünftig nicht großartig ändern. I. d. R. brauche ich auch nur die ersten beiden, alle drei zusammen selten.
 
Mr. Snoot schrieb:
Die Tabellen haben 8 (bereich), 37 (kapitel) und 118 (absätze) Zeilen; das wird sich zukünftig nicht großartig ändern. I. d. R. brauche ich auch nur die ersten beiden, alle drei zusammen selten.

Da sind wir doch schon bei 8*37 Querys (296), das ist schon viel zu viel!
So vllt. 20 Querys pro Seitenaufbau sollten als ungefähre Grenze genutzt werden.
 
Okay, dann werd ich mal ein Beispiel auf zwei Varianten aufbauen und die Zeit messen.
 
Dabei solltest aber nicht übersehen, dass eine gute Seite mehr als 100 Anfragen pro Sekunde leicht wegsteckt. Das wären hier dann schon fast 3000 Queries/s - nur für diese eine Funktion.

Um einen kurzen Eindruck zu bekommen was 100 pro Sekunde heißt.. mein Server liefert bei statischen Seiten fast 100.000 Anfragen pro Sekunde aus :) Das sind 100 schon enorm langsam im Vergleich.
 
Zuletzt bearbeitet:
Singleton bringt hier nur dann etwas, wenn in einem Seitenaufruf das Zeug gleich mehrfach berechnet wird. Hier bietet sich eher ein Dateicache an. Aber ganz ehrlich.. wenn die Anfrage richtig ausgeführt wird (also ohne Schleife) dann geht es auch problemlos ohne Cache.
 
Zurück
Oben