6

Ich habe eine DELETE-Abfrage, die ich auf PostgreSQL 9.0.4 ausführen muss. Ich finde, dass es performant ist, bis es 524.289 Zeilen in einer Subselect-Abfrage trifft.Postgres Materialize verursacht schlechte Leistung in löschen Abfrage

Zum Beispiel bei 524.288 keine verwendet materialisierte Ansicht ist und die Kosten sehen sehr gut aus:

 
explain DELETE FROM table1 WHERE pointLevel = 0 AND userID NOT IN 
(SELECT userID FROM table2 fetch first 524288 rows only); 
               QUERY PLAN 
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
Delete (cost=13549.49..17840.67 rows=21 width=6) 
    -> Index Scan using jslps_userid_nopt on table1 (cost=13549.49..17840.67 rows=21 width=6) 
     Filter: ((NOT (hashed SubPlan 1)) AND (pointlevel = 0)) 
     SubPlan 1 
      -> Limit (cost=0.00..12238.77 rows=524288 width=8) 
       -> Seq Scan on table2 (cost=0.00..17677.92 rows=757292 width=8) 
(6 rows) 

aber sobald ich 524.289 getroffen, die materialisierte Ansicht ins Spiel kommt und die DELETE-Abfrage wird viel teurer:

 
explain DELETE FROM table1 WHERE pointLevel = 0 AND userID NOT IN 
(SELECT userID FROM table2 fetch first 524289 rows only); 

    QUERY PLAN 

----------------------------------------------------------------------------------------------------------- 
Delete (cost=0.00..386910.33 rows=21 width=6) 
    -> Index Scan using jslps_userid_nopt on table1 (cost=0.00..386910.33 rows=21 width=6) 
     Filter: ((pointlevel = 0) AND (NOT (SubPlan 1))) 
     SubPlan 1 
      -> Materialize (cost=0.00..16909.24 rows=524289 width=8) 
       -> Limit (cost=0.00..12238.79 rows=524289 width=8) 
         -> Seq Scan on table2 (cost=0.00..17677.92 rows=757292 width=8) (7 rows) 

ich rund um das Thema gearbeitet durch eine statt in der Unterauswahlabfrage JOIN mit:

SELECT s.userid 
FROM table1 s 
LEFT JOIN table2 p ON s.userid=p.userid 
WHERE p.userid IS NULL AND s.pointlevel=0 

Ich bin jedoch immer noch interessiert zu verstehen, warum die Materialisierung die Leistung so drastisch verringert.

Antwort

4

Meine Vermutung ist, dass bei rows=524289 der Speicherpuffer gefüllt ist, so dass die Unterabfrage auf der Festplatte materialisiert werden muss. Daher der dramatische Anstieg der benötigten Zeit.

Hier können Sie mehr über die Konfiguration der Speicherpuffer lesen: http://www.postgresql.org/docs/9.1/static/runtime-config-resource.html
Wenn Sie mit work_mem spielen, werden Sie den Unterschied in der Abfrageverhalten sehen.

Die Verwendung von Join in der Unterabfrage ist jedoch ein viel besserer Weg, um die Abfrage zu beschleunigen, da Sie die Anzahl der Zeilen an der Quelle selbst begrenzen oder einfach zuerst XYZ-Zeilen auswählen und dann Prüfungen durchführen.