Frage

Ich versuche, einen einfachen Weg zu finden, um die Leistung für sehr aktive Foren zu verbessern, in denen es eine große Anzahl von Beiträgen gibt und MySQL keine Tabellensortierungen mehr im Speicher durchführen kann und Indizes nicht voll auszunutzen scheint.

Diese einfache Abfrage findet den neuesten Beitrag in jedem Thema, damit ein Benutzer feststellen kann, ob er seitdem Antworten hat (durch späteren Vergleich der topic_time )

SELECT p.*, MAX(post_time) as post_time FROM forum_posts AS p   
WHERE p.poster_id = '1' AND p.post_status = '0' 
GROUP BY p.topic_id  
ORDER BY post_time DESC 
LIMIT 50

einfacher, flacher Tisch sieht ungefähr so aus

post_id | poster_id | topic_id | post_status | post_time | post_text

Die Leistung fällt jedoch auseinander, wenn es eine Million Posts gibt und der Benutzer selbst Zehntausende von Posts hat.MySQL kann die Tabelle entweder nicht mehr im Speicher sortieren oder es sind viel zu viele Zeilen zum Scannen vorhanden.In der realen Welt kann es bis zu 3 Sekunden dauern, was meiner Meinung nach nicht akzeptabel ist, da es die CPU während dieser Zeit anspringt und alle anderen verlangsamt.

Ich kann natürlich jede Kombination von Index erstellen, aber mysql scheint meistens eine Kombination aus zu verwenden

poster_id + post_time 

Es wählt also nur die 50k Beiträge eines Benutzers aus der Million aus und beginnt dann mit der Gruppierung nach topic_id und der Sortierung.Seltsamerweise scheint das Hinzufügen von topic_id zum Indexmix der Leistung nicht zu helfen, obwohl es die Reihenfolge der Indexfelder sein könnte?

Ich habe versucht, stattdessen einen äquivalenten JOIN zu schreiben, damit ich mehr als einen Index verwenden kann, aber ich habe Probleme damit, dass jede Seite nach post_status und poster gefiltert werden muss.

Ich dachte, es wäre schneller, zumindest für die ersten paar Seiten, wenn MySQL dazu gebracht werden könnte, die Daten ZUERST über ihren Index nach post_time zu sortieren und dann die eindeutige topic_id für den Benutzer in absteigender Reihenfolge auszuwählen.Ich denke, das würde eine Unterabfrage erfordern und nicht sicher, ob eine 50k Ergebnis-Unterabfrage besser wäre, braucht immer noch eine temporäre Tabelle.

Natürlich wäre eine grundlegende Lösung, das Kerndesign so zu erweitern, dass es eine weitere Tabelle gibt, in der nur die maximale post_time für jeden Benutzer in jedem Thema gespeichert ist, aber dies ist eine viel zu große Änderung, es sei denn, es kann keine andere Lösung gefunden werden.

Vielen Dank für alle Vorschläge!


beispiel aus der realen Welt hinzufügen und ERKLÄREN:

langsames Protokoll

# Query_time: 2.751334  Lock_time: 0.000056 Rows_sent: 40  Rows_examined: 48286
SELECT   p.*, MAX(post_time) as post_time FROM forum_posts AS p   WHERE p.poster_id = '2' AND p.post_status = '0' GROUP BY p.topic_id  ORDER BY post_time DESC LIMIT 7000, 40;

erklären

select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
SIMPLE          p   ref poster_time poster_time 4   const   27072   Using where; Using temporary; Using filesort
War es hilfreich?

Lösung

Korrigieren Sie zunächst Ihre Abfrage, um bestimmte Ergebnisse zu liefern:

SELECT p.topic_id, 
       MAX(post_time) as post_time 
FROM forum_posts AS p   
WHERE p.poster_id = '1' AND p.post_status = '0' 
GROUP BY p.topic_id  
ORDER BY post_time DESC 
  LIMIT 50 ;

Probieren Sie es dann aus, nachdem Sie einen Index hinzugefügt haben (post_status, poster_id, topic_id, post_time).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top