Vinzenz Mai: SQL Abfrage performance

Beitrag lesen

Hallo Gerd,

es geht um ein Forum. Da habe ich eine Übersicht über die letzten Beiträge. Funktioniert auch, nur dass da viel zu viele abfragen gemacht werden. Bin mir sicher, dass es auch besser geht, nur nicht wie :)

es ist möglich, dass es möglich ist.
Es ist möglich, dass es nicht möglich ist.

Das hängt davon ab, was Dein Datenbankmanagementsystem (DBMS) kann.

SELECT beitrag.thread_id, thread.forum_id, thread.beschreibung, thread.titel,  beitrag.time, user.username
FROM thread, beitrag, user
WHERE thread.id=beitrag.thread_id AND beitrag.von_id=user.id AND thread.lasttime=beitrag.time AND thread.forum_id!='13' AND thread.forum_id!='14'
GROUP BY beitrag.thread_id
ORDER by thread.lasttime DESC LIMIT 8

  
Dieses Statement sagt mir, dass es sich bei Deinem DBMS um MySQL handelt. Jedes andere DBMS weist Dein Statement als fehlerhaft zurück. Schreiben wir es ein wenig mit expliziter Join-Syntax, die ich persönlich wesentlich lesbarer finde, um:  
  
~~~sql
SELECT  
    b.thread_id,  
    t.forum_id,  
    t.beschreibung,  
    b.time,  
    u.username  
FROM thread t           -- Tabellen-Aliasnamen ersparen Schreibarbeit  
                        -- und können die Übersicht erhöhen  
INNER JOIN beitrag b    -- explizite JOIN-Syntax  
ON t.id = b.thread_id  
INNER JOIN user u  
ON b.von_id = u.id  
WHERE                   -- damit lässt sich die Einschränkung viel besser sehen  
    t.forum_id NOT IN (13, 14)  -- NOT IN finde ich übersichtlicher als Deine Und-Verknüpfung  
                                -- von Ungleichheiten.  
GROUP BY  
    b.thread_id,        -- In der Spaltenliste dürfen _nur_ Spalten  
    t.forum_id,         -- auftreten, nach den gruppiert wird oder  
    t.beschreibung,     -- auf die eine Aggregatsfunktion angewandt wird.  
    b.time,             -- Da Du keine einzige Aggregatsfunktion anwendest,  
    u.username          -- muss nach allen Spalten gruppiert werden.  
ORDER BY t.lasttime DESC  
LIMIT 8  

Wenn diese Abfrage nicht das gewünschte Ergebnis liefert, dann liefert Dir Deine Abfrage nur zufälligerweise das gewünschte Ergebnis und kann auch andere Ergebnisse zurückliefern. Siehe Handbuch.

Ich halte es für keine gute Idee, Spalten bequemlichkeitshalber in der GROUP-BY-Klausel wegzulassen. Es führt oft zu Fehlern, wozu es eine Menge Threads im Archiv gibt.

Ich habe meine Zweifel, ob Deine Spalte

beitrag.time

wirklich garantiert den richtigen Wert aufweist. Ich vermute, das ist nicht der Fall. Vermutlich solltest Du diesen Wert (wahrscheinlich die Zeit des ersten Beitrags im Thread) und auch den Benutzernamen zu diesem Beitrag mit einem korrelierten Subselect ermitteln.

In der Schleife wo die Beiträge ausgelesen werden wird bei jedem Durchlauf folgende Abfrage gemacht, damit ich die anzahl der Gesamtbeiträge bekomme, um einen Link auf die letzte Seite des Threads zu setzen:

Eine Anzahl von Gesamtbeiträgen kann man normalerweise bequem mit einem Subselect ermitteln. Da ich Deine Tabellenstruktur nicht kenne, kann ich Dir nicht weiterhelfen. Da müssen mehr Informationen her, am besten die relevanten Spalten Deiner drei Tabellen mit ein paar Beispieldatensätzen, dazu das gewünschte Resultat - mit der Begründung, warum Du genau dieses haben möchtest.

Bevor ich es vergesse: MySQL unterstützt Subselects ab Version 4.1, siehe verlinkter Handbuchabschnitt. Deshalb wäre es eine gute Idee von Dir, uns zu sagen, welche Version Du verwendest.

Freundliche Grüße

Vinzenz