Hi zusammen,
ich habe folgendes Performanceproblem mit Views und Joins mit der Postgre 8.2.4.
Ausgangslage :
Es existiert ein View, der ein ziemlich komplexes Datenmodell als Tabelle darstellt (Vererbung usw.) Die zugrunde liegende Tabelle hat ca. 14700 Einträge und wenn ich mir alle Einträge selektiere dauert das 31,5 Sekunden oder ca. 2.1 ms pro Datensatz, alles ok.
Select * from v_artikel
Wenn ich einen einzelnen Datensatz selektiere dauert das um die 15 ms. Wenn ich den Overhead wegrechne usw. ist das auch ok.
Select * from v_artikel where Artikelnr = 'XYZ'
Jetzt habe ich eine Tabelle mit Auftragspositionen, in der natürlich Artikel enthalten sind (auf der Artikelnr liegt natürlich ein Index). Meine Abfrage um die Positionen eines Auftrags zu selektieren sieht jetzt so aus:
Select *
from Auftragspos ap inner Join v_artikel a ON ap.artikelnr = a.artikelnr
Where AuftragsNr = 12345
Der Auftrag hat 14 Positionen und ich hätte jetzt erwartet, im schlechtesten Fall würde die Abfrage so 0,5 Sekunden laufen. In Wirklichkeit benötigt sie aber 26 Sekunden.
Meiner Ansicht nach liegt das Problem darin, dass der Optimizer erst das komplette Resultset des Views aufbaut, bevor er über den Join daran geht die Einträge aus v_artikel wieder rauszuschmeissen, die er nicht braucht.
Jetzt ändere ich das Statement folgendermaßen ab:
Select *
from Auftragspos ap inner Join v_artikel a ON ap.artikelnr = a.artikelnr
Where AuftragsNr = 12345 and
a.artikelnr in (String mit den Artikelnummern)
oder konkret
Select *
from Auftragspos ap inner Join v_artikel a ON ap.artikelnr = a.artikelnr
Where AuftragsNr = 12345 and
a.artikelnr in ('AAA,'BBB','CCC', ...)
Vorher selektiere ich alle Artikelnummern aus der Tabelle Auftragpos und baue diese zu einem String zusammen ('AAA,‘BBB’,‘CCC’, …)
Führt man dieses Statement aus, das genau das gleiche Ergebnis hat beträgt die Ausführungszeit nur noch 78 ms.
Anscheind reagiert hier der Optimizer und merkt von vorneherein, dass er nicht alle Datensätze von v_artikel benötigt, sondern nur die angegebenen.
Allerdings auch nur, wenn ich die Artikelnummern statisch ins Statement reinschreibe.
Folgendes Statement:
Select *
from Auftragspos ap inner join v_artikel a ON ap.Artikelnr = a.artikelnr
Where
AuftragsNr = 12345 and
a.artikelnr in (Select distinct artikelnr from Auftragspos Where ka_nr = 12345 )
ist genauso langsam, wie die erste Version.
Die gefundene Lösung ist natürlich eine Möglichkeit, jedoch alles andere als elegant. Daher die Frage: gibt es hier eine Möglichkeit dem Optimizier “zu sagen” was er tun soll, oder sonst irgendwas, was ich bisher übersehen habe ?
Vielen Dank schon mal im Vorraus für die Hilfe.