2010-10-26 12 views
5

Ich habe diese Abfrage in einer Tabelle mit etwa 100k Datensätze, es läuft ziemlich langsam (3-4 s), wenn ich die Gruppe herausnehmen ist es viel schneller (weniger als 0,5 s). Ich bin ganz bei Verlust, was dies zu tun zu beheben:mysql "Gruppe von" sehr langsame Abfrage

SELECT msg.id, 
     msg.thread_id, 
     msg.senderid, 
     msg.recipientid, 
     from_user.username AS from_name, 
     to_user.username AS to_name 
FROM msgtable AS msg 
LEFT JOIN usertable AS from_user ON msg.senderid = from_user.id 
LEFT JOIN usertabe AS to_user ON msg.recipientid = to_user.id 
GROUP BY msg.thread_id 
ORDER BY msg.id desc 

msgtable hat Indizes auf thread_id, id, senderid und recipientid.

kehrt erklären:

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE msg ALL NULL NULL NULL NULL 162346 Using temporary; Using filesort 
1 SIMPLE from_user eq_ref PRIMARY PRIMARY 4 db.msg.senderid 1  
1 SIMPLE to_user eq_ref PRIMARY PRIMARY 4 db.msg.recipientid 1 

Irgendwelche Ideen, wie dies zu beschleunigen, während das gleiche Ergebnis zurückkehrt (es gibt mehrere Nachrichten pro Thread, ich will in dieser Abfrage pro Thread nur eine Nachricht zurück).

Dank im Voraus.

+1

Was ist mit 'usertable' Indizes? Können Sie bitte 'EXPLAIN ' ausführen und die Ergebnisse veröffentlichen? – Frankie

+1

In der Regel müssen Sie alle in SELECT erwähnten Spalten deklarieren, die nicht durch Aggregatfunktionen (COUNT, SUM, MIN, MAX usw.) in GROUP BY gekapselt sind. Würde 'DISTINCT' Ihnen in dieser Situation besser dienen? –

+0

Warum die linke beitreten? Würde nicht jede Nachricht einen Empfänger und einen Absender erfordern? –

Antwort

1

versuchen Sie dies:

select m.thread_id, m.id, m.senderid, m.recipientid, 
     f.username as from_name, t.username as to_name 
from msgtable m 
join usertable f on m.senderid = f.id 
join usertable t on m.recipientid = t.id 
where m.id = (select MAX(id) from msgtable where thread_id = m.thread_id) 

Oder diese:

select m.thread_id, m.id, m.senderid, m.recipientid, 
     (select username from usertable where id = m.senderid) as from_name, 
     (select username from usertable where id = m.recipientid) as to_name 
from msgtable m 
where m.id = (select MAX(id) from msgtable where thread_id = m.thread_id) 

Warum die Benutzertabellen wurden verbunden übrig? Kann eine Nachricht ein von oder zu fehlen? ..

+0

Dank einer Million, habe ich beide Optionen ausprobiert - erste Option ca. 1,5s, zweite Option ca. 2s. was kann ich noch tun, um es noch mehr herunterzubringen? –

+0

@Sherif, brauchen Sie wirklich alle Threads auf einmal? ... Gibt es eine Datetime-Spalte, die verwendet werden könnte, um die benötigten Daten zu reduzieren? – Fosco

+0

@Forsco, tatsächlich wird diese Abfrage in eine Auswahlanzahl (*) der Abfrage durch eine Paging-Klasse übersetzt - ja, ich brauche alle Threads, da dies für eine Admin-Funktion ist ... –

0

Das größte Problem ist, dass Sie keine brauchbaren Indizes auf msgtable haben. Erstellen Sie einen Index auf mindestenssenderid und recipientid, und es sollte die Geschwindigkeit Ihrer Abfrage unterstützen, da es die Anzahl der Ergebnisse beschränkt, die gescannt werden müssen.

+0

Ich habe Indizes für diese, aktualisierte Frage oben. –