Mysql query verbessern

Hallo ich habe ein Problem ich habe ein ziemlich lastenaufwendiges Mysql-Querry. Ich wollte mal Fragen ob jmd. weiß wie ich vielleicht das querry umschreiben könnnte um die Last zu reduzieren. Oder geht es nicht besser?

Mysql Querry:

select distinct skadate\_members.member\_id userid, skadate\_members.username username, skadate\_members.lastvisit lastactivity, skadate\_members.member\_id avatar, skadate\_members.member\_id link, cometchat\_status.message, cometchat\_status.status 
from skadate\_friends, skadate\_members 
left join cometchat\_status 
on skadate\_members.member\_id =cometchat\_status.userid 
where skadate\_friends.pending = 0 
and ( skadate\_friends.member\_id =1
or skadate\_friends.friend\_id =1
and ( (skadate\_friends.friend\_id = skadate\_members.member\_id) 
or (skadate\_friends.member\_id = skadate\_members.member\_id)) ")

Tabellenstruktur:
skadate_members
member_id(int(9)) username(varchar(32)) lastvisit(int(10))

skadate_friends
member_id(int(9)) member_id(int(9)) request_date((int(10)) pending((int(9)))

cometchat_status
userid(int(10)) message(text) status(varchar(10))

Hallo Thomas,

nur die Anfrage reicht nicht, um Performance-Probleme beurteilen zu können. Wichtiger sind dafür solche Fragen: Wie groß sind deine Tabellen? Wieviele verschiedene Werte haben die Spalten? Hast du schon Indexe auf Spalten angelegt, um die Auswertung (vor allem der Join-Prädikate) zu unterstützen?

Was mir durch bloßen Anschauen deiner Frage spanisch vorkommt, ist folgendes (ein wenig vereinfacht):

select distinct skadate_ members.*, cometchat_ status.*
from skadate_friends, skadate_members left join cometchat_status on …
where skadate_ friends.pending = 0
and ( skadate_ friends.member_id =1 or [andere Bedingung])

Das bedeutet, für jede Zeile aus „friends“ mit „friends.member_id = 1“ kommen alle members/status-Kombinationen in die Ausgabe (wieviele sind das?). Ich kann mir kaum vorstellen, dass das gewollt ist. Es fehlt hier anscheinend eine Join-Bedingung (oder du bist bei deiner Klammersetzung und fehlenden Einrückung durcheinandergekommen: „and“ bindet stärker als „or“!).

Viele Grüße,

Andreas

Hallo zurück hier erst mal die Werte.

skadate_members hat 46 Spalten und 11 213 Datensätze.
skadate_friends hat 4 Spalten und 21 962 Datensätze.
cometchat_status hat 4 Spalten und 413 Datensätze.
Hoffe das dir diese Werte reichen. Wenn ich die obrige Mysql-Abfrage ausführe kriege ich sowas " Zeige Datensätze 0 - 29 (11,213 insgesamt, die Abfrage dauerte 0.0768 sek.)"

Das kann schon sein das diese Mysql abfrage was spanisches macht aber es kommt das raus was ich will^^. Das Problem am Anfang war bei dieser MysQL abfrage das ich nur die Freunde von Benutzer „1“ bekommen habe die er als Freunde hizugefügt hat.
Hab aber nicht die Freunde bekommen wo jemand anderes den Benutzer „1“ als Freund hizugefügt hat deshalb die ganzen or and usw.
Dann habe ich das mit UNION versucht zu lösen aber da wurde mir gesagt das UNION ganz schlecht ist. Also habe ich es so versucht, aber es überlastet immer noch den Datenbankserver. Die Indexes sind gesetzt.

Hi,
der Query-Optimizer vom MySQL ist in einigen Situationen richtig schlecht.

Schau dir den Ausführungsplan deiner Abfrage mit „EXPLAIN“ an.
Mit dem USE INDEX kannst du dann den Optimizer vorgeben welchen Index er nimmt, falls er es nicht tun sollte. Ich gehe mal davon aus, dass die Felder in den where Bedingungen alle eine Index haben, sofern sie nicht sowieso der Primärschlüssel sind.

Gruss
Joey

Hallo Thomas,

skadate_members hat 46 Spalten und 11 213 Datensätze.
skadate_friends hat 4 Spalten und 21 962 Datensätze.
cometchat_status hat 4 Spalten und 413 Datensätze.

danke; zusammen mit deiner Beschreibung, was die Anfrage machen soll, bekomme ich ein besseres Bild von der Situation. Ist folgendes richtig?

„members“ enthält alle Mitglieder (irgendeiner Community), „friends“ ist eine n:m-Beziehung zwischen Mitgliedern, die gerichtet ist, und stellt eine Einladung zur Freundschaft dar, die entweder noch unbeantwort ist (pending = 1) oder schon angenommen (pending = 0). In „status“ ist für einige wenige der Mitglieder (4 %; alle die online sind?) ihr Status hinterlegt.

Du möchtest alle Freunde von Mitglied 1 finden, wobei du „Freundschaft“ über beide Richtungen der Beziehung in „friends“ definierst (es sollen also sowohl Mitglieder gefunden werden, die Mitglied 1 erfolgreich eingeladen hat, als auch solche, die selbst Mitglied 1 erfolgreich eingeladen haben). Zu den Mitgliedern, zu denen es einen Status gibt, soll zusätzlich dieser Status ausgegeben werden.

Soweit richtig?

Das hätte ich an deiner Stelle so formuliert, damit die Verständlichkeit und Übersichtlicht gewahrt bleibt:

select m.member\_id userid, m.username username, m.lastvisit lastactivity,
 m.member\_id avatar, m.member\_id link, s.message, s.status 
from skadata\_members m left join cometchat\_status s on m.member\_id = s.userid
where m.member\_id in (
 select friend\_id
 from skadate\_friends
 where member\_id = 1
 and pending = 0

 union all

 select member\_id
 from skadate\_friends
 where friend\_id = 1
 and pending = 0
)

Dann hätte ich darauf geachtet, dass auf friends.member_id, friends.friend_id, members.member_id und status.userid Indexe existieren.

Wenn dann wider Erwarten die Performance noch nicht stimmt, würde ich mir wie Joey die Ausführungspläne anschauen.

Viele Grüße,

Andreas

PS:

Dann habe ich das mit UNION versucht zu lösen aber da wurde
mir gesagt das UNION ganz schlecht ist.

Auf solche pauschalen Aussagen sollte man nicht blind vertrauen. Auf jeden Fall solltest du den Unterschied zwischen UNION und UNION ALL kennen (ersteres eliminiert Duplikate, was teuer sein kann). In meiner Anfrage ist es egal (sofern der Optimierer gut ist; ich weiß nicht, wie es bei MySQL da aussieht).