Stefan: Langsames SQL; Wie schneller machen?

Beitrag lesen

Hi Jan

Hab mir grad mal das einfach Beispiel für Case in meinem "NittyGritty SQL"-Buch nachgeschlagen. Bin da Deiner Meinung, dass es - wenn überhaupt - mit einem nicht grad schönen Case When gehen müsste.

Also ich habe grade nochmal genauer drüber nachgedacht und des Rätsels Lösung ist eine vereinfachte Form der Case-When (die einfache If) in Verbindung mit einer Summenformel... :o)

Aber bevor ich dazu komme, würde ich gerne noch etwas zu Deinen Tabellen anmerken. Ich gehe ja davon aus, dass die Tabellen noch mehr Felder beinhalten, Du aber nur die relevanten hier hergeschrieben hast. Nur eines ist mir aufgefallen. Du denkst, jede Tabelle muss einen Primärschlüssel haben, der in einem Feld ist, kann das sein? Deine Beziehnungstabelle sieht nämlich durch das Feld BID (=BeziehungsID??) so aus. Hier reichen die Felder KID und GID als zusammengesetzer Primärschlüssel. Das bedeutet: Die Kombination aus KID und GID ist eindeutig und darf nur einmal vorliegen, was auch logisch ist, weil jeder Kunde nur einmal in einer Gruppe drin sein kann, oder? ;) (Entweder er ist drin oder er ist es nicht, drinner als drin wäre wohl vom Thema abgekommen *g*) Und durch Deine Tabelle mit der BID ermöglichst Du genau diesen Fall, das ein Kunde mehrmals in einer Gruppe sein kann. Also nimm das Feld einfach raus :o)

Deine Tabellen sehen dann so aus:

1. Kundentabelle ( KID, Firma );
2. Gruppentabelle ( GID, Gruppenname );
3. Beziehungstabelle ( KID, GID );

Darauf aufbauend (mit diesen Namen) kannst Du für Deine Lösung folgendes SQL Statement ausführen:

SELECT
 Kundentabelle.Firma,
 SUM(IF(Beziehungstabelle.GID=<IDGruppe1>,1,0)),
 SUM(IF(Beziehungstabelle.GID=<IDGruppe2>,1,0)),
 SUM(IF(Beziehungstabelle.GID=<IDGruppe3>,1,0)),
 SUM(IF(Beziehungstabelle.GID=<IDGruppe4>,1,0)),
 COUNT(*)

FROM
 Kundentabelle

LEFT JOIN
 Beziehungstabelle ON Kundentabelle.KID = Beziehungstabelle.KID

GROUP BY
 Kundentabelle.KID

ORDER BY
 Kundentabelle.Firma ASC;

Hinweis: <IDGruppe1> usw. sind natürlich durch die entsprechenden IDs zu ersetzen, bevor das gute Stück ausgeführt wird. Du kannst hinter die Felder auch immer noch ein 'AS <FELDNAME>' setzen, aber das verlangsamt die ganze Sache wieder deswegen lass ich es raus.

Wenn Du dieses Query anwenden willst, dann nutze etwa diesen PHP Code:

<?php

// Datenbankverbindung aufbauen
$db = mysql_connect( <host>:<port>, <user>, <pass> );
      mysql_select_db( <dbname> );

// Query definieren
$query = <<<ENDSQL
SELECT
 Kundentabelle.Firma,
 SUM(IF(Beziehungstabelle.GID=<IDGruppe1>,1,0)),
 SUM(IF(Beziehungstabelle.GID=<IDGruppe2>,1,0)),
 SUM(IF(Beziehungstabelle.GID=<IDGruppe3>,1,0)),
 SUM(IF(Beziehungstabelle.GID=<IDGruppe4>,1,0)),
 COUNT(*)

FROM
 Kundentabelle

LEFT JOIN
 Beziehungstabelle ON Kundentabelle.KID = Beziehungstabelle.KID

GROUP BY
 Kundentabelle.KID

ORDER BY
 Kundentabelle.Firma ASC;
ENDSQL;

// Query ausfuehren
$res = mysql_query( $query, $db );

// Ergebnisliste ausgeben
if( mysql_num_rows( $res ) ) {
 while( list( $firma, $in_gruppe1, $in_gruppe2, $in_gruppe3, $in_gruppe4, $anzahl_gruppen ) = mysql_fetch_row( $res ) ) {
  // Hier kannst Du dann mit den oben erstellten Variablen arbeiten...
 }
}

// Datenbankverbindung schließen
mysql_close( $db );

Hinweis: In der Praxis sieht es dann so aus, dass Du erst den Tabellenkopf erstellst, dann die Ergebniszeilen ausgibst und dann die Tabelle beendest, aber das wirst Du Dir selbst zusammenreimen können :o)

Viele Grüße

Stefan