dedlfix: /MySQL: JOIN optimieren

Beitrag lesen

Hi!

SELECT titel.titelUrl, playcount, score, laenge FROM userTitel LEFT JOIN titel ON titel.titelUrl = userTitel.titelUrl WHERE userName = 'XXXX'
Du könntest dafür sorgen, dass die für die Einschränkungen verwendeten Spalten (in diesem Fall titel.titelUrl, userTitel.titelUrl und userTitel.userName) mit vernünftigen Indizes versehen sind, um die Suche zu beschleunigen.

In Indexe dachte ich auch zuerst, aber dann sah ich weiter unten, dass welche vorhanden sind und laut EXPLAIN auch verwendet werden. Für userTitel.titelUrl braucht es für diese Abfrage keinen Index. userTitel steht auf der linken Seite, was heißt, dass beim Left Join alle Datensätze genommen werden. Die passenden dazu müssen aus titel gesucht werden, und auf titel.titelUrl liegt der Primärindex, der laut EXPLAIN auch verwendet wird. Für die Einschränkung mit der WHERE-Klausel wird userTitel.userName verwendet. Dieses Feld hat einen Index, der ebenfalls verwendet wird.

Und nun? Meine Gedankengang ist, dass die WHERE-Klausel erst nach der Erstellung des Join-Produkts ausgewertet wird, was bei der Menge der Datensätze die Zeit verbraucht. Allerdings könnte vielleicht auch der eingebaute Optimierer so clever sein, sich lediglich auf die geWHEREten Datensätze zu beschänken. Meine Untersuchen wären nun wie folgt: Lediglich zum Schauen, ob das Punkte bringt, würde ich die Bedingung im WHERE in die Join-Bedingung verlagern.

ON titel.titelUrl = userTitel.titelUrl AND userName = 'XXXX'

Hier vermute ich, dass sich dadurch das Join-Produkt nur auf die XXXX-Datensätze beschränkt.

Da aus der Tabelle titel zu jedem userTitel-Datensatz nur (keine oder) eine Zeile kommen kann, wäre der nächste Test die schon vorgeschlagene korrelierte Subquery-Version. Wenn es - wie in der gezeigten Abfrage - lediglich um das Feld laenge aus titel geht, würde ich die Subquery nach diesem Feld in die SELECT-Klausel stellen. Wenn noch weitere Felder benötigt werden, wird es aber recht aufwendig, dafür je eine eigene Subquery zu notieren. Dann kommt man mit einem Join günstiger. Allerdings müsste man dann untersuchen, wenn mein erster Vorschlag nichts bringt, wie man die zu joinende Datenmenge einschränken kann. Vielleicht so:

SELECT felder FROM (SELECT * FROM userTitel WHERE userName = 'XXXX') AS ut LEFT JOIN titel ...

Damit erhoffe ich mir, dass die Join-Menge auf den gewünschten User beschränkt wird.

Lo!