Gerd H.: SQL Abfrage performance

Hallo,

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 :)

Hier die aktuelle Version:

// Hier die Beiträge

  
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  

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:

  
SELECT beitrag.b_id  
FROM beitrag, thread, user  
WHERE beitrag.thread_id='" . mysql_real_escape_string($thread_id) . "' AND thread.forum_id='" . mysql_real_escape_string($forum_id) . "' AND beitrag.thread_id=thread.id AND beitrag.von_id=user.id  

Das sind dann insgesammt bei jedem Aufruf nur an dieser Stelle 9 Abfragen, wo bestimmt auch eine sein könnte :)

Kann mir da jemand was basteln :)

Danke Gerd

  1. 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

    1. Leider erhalte ich nicht das gewünschte Ergebnis. Aber danke für die sehr ausführliche Antwort.

      Als Ergebnis erhalte ich mehrere Datensätze des selben Themas und da soll ja pro Thema maximal ein Ergebnis des letzen Beitrags angzeigt werden.

      Außerdem brauchte deine Abfrage ca. 0,65 Sekunden ...meine im Vergleich dazu weniger als die Hälfte der Zeit: 0,24 Sekunden

      Aber deine finde ich echt übersichtlicher :)

      Hier die Struktur meiner Tabellen:

        
      mysql> SELECT * FROM beitrag LIMIT 1;  
      +------+-----------+--------+-----------+----------+---------------------------------+------------+----+  
      | b_id | thread_id | von_id | edit_time | edit_von | kommentar                       | time       | ip |  
      +------+-----------+--------+-----------+----------+---------------------------------+------------+----+  
        
      mysql> SELECT * FROM thread LIMIT 1;  
      +----+---------+--------------------+---------------------------------------+--------+----------+---------+------------+  
      | id | aufrufe | titel              | beschreibung                          | closed | forum_id | wichtig | lasttime   |  
      +----+---------+--------------------+---------------------------------------+--------+----------+---------+------------+  
        
      
      

      Und ja es geht hier um MySQL 4.1 ! Ich vergesse es echt immer anzugeben :)

      Als ergebnis möchte ich halt die letzten Beiträge haben. Zusätzlich brauche ich die Anzahl der Beiträge in dem jeweiligen Thread, damit ich einen direkten Link auf die letzte Seite setzen kann.

      PS: das mit den "NOT IN" werde ich jetzt schon übernehmen :)