Vinzenz Mai: Query optimieren / mysql 5

Beitrag lesen

Hallo Ilja,

Eher verwundert mich, dass er nur eine Join-Bedingung aber vier Tabellen/Aliase hat. Oder zählen die beiden BETWEEN-Bedingunen zu den JOIN-Bedingungen und nicht zu den datensatzeinschränkenden? Das Hauptproblem ist ja, dass er hier wohl irgendwelche riesigen kartesischen Produkte bekommt, weil er nicht richtig verknüpft und/oder einschränkt.

ja, und deswegen auch die explizite schreibweise, die bringt sowas immer sehr schnell ans tageslicht.

Du sagst ja gerne "Joins sind böse.". Ist dies hier nicht der Fall - und vielleicht nur MySQLs hoher Verbreitung und ehemaliger Subselect- und SP-Unfähigkeit geschuldet?

Wenn ich mir das von mir umgeschriebene

SELECT  
    node.payload  
FROM  
    000node parent  
INNER JOIN  
    000node node  
ON  
    node.lft BETWEEN parent.lft AND parent.rgt  
WHERE  
    parent.payload = 5895  
ORDER BY  
    node.lft;  

ansehe, so ist es in Wirklichkeit gar kein Join, sondern durch folgende Statements ersetzbar:

SELECT  
   lft,  
   rgt  
FROM  
   000node  
WHERE  
   <bedingungen, die Ausgangsknoten eindeutig identifizieren>;

Wenn es genau einen Datensatz gibt, fülle die Variablen lower und upper mit den Werten aus lft bzw. rgt. und gebe anschließend das Resultset von

SELECT  
    kommagetrennte,  
    liste,  
    gewünschter,  
    spalten  
FROM  
    000node  
WHERE  
    lft BETWEEN upper AND lower

zurück, was über eine SP problemlos machbar sein sollte. MySQLs SELECT ... INTO unterstützt das Füllen von Variablen, die man anschließend in einem serverseitigen Prepared Statement nutzen könnte (kein dynamisches SQL in einer SP in MySQL).

alternativ:

SELECT  
    node.payload  
FROM  
    000node node  
WHERE  
    node.lft BETWEEN (SELECT  
                          parent.lft  
                      FROM  
                          000node parent  
                      WHERE  
                          parent.payload = 5895  
                      )  
             AND     (SELECT  
                          parent.rgt  
                      FROM  
                          000node parent  
                      WHERE  
                          parent.payload = 5895  
                      )  

in der Hoffnung, dass der Optimizer merkt, dass er die Subselects nur einmal auszuführen braucht (und zwei Subselects, wo mir eines lieber wäre, aber mir fällt gerade nichts ein, womit ich dieses umgehen könnte). Andere DBMS kennen ja eine WITH-Klausel, die man für genau solche Zwecke wunderbar nutzen könnte.

Freundliche Grüße

Vinzenz