6

Ho una query DELETE che devo eseguire su PostgreSQL 9.0.4. Sto trovando che è performante fino a quando non colpisce 524.289 righe in una query di sottoselezione.Postgres Materialize causa scarse prestazioni nella query di eliminazione

Per esempio, a 524.288 non c'è vista materializzata usato e il costo sembra piuttosto buono:

 
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) 

Tuttavia, non appena mi ha colpito 524.289, la vista materializzata entra in gioco e la query DELETE diventa molto più costoso:

 
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) 

ho lavorato tutto il problema utilizzando un JOIN nella query sub-select invece:

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

Tuttavia, sono ancora interessato a capire perché il materialize diminuisce le prestazioni in modo così drastico.

risposta

4

La mia ipotesi è che al rows=524289 il buffer di memoria è pieno, quindi la subquery deve essere materializzata sul disco. Da qui il drammatico aumento del tempo necessario.

Qui si può leggere di più sulla configurazione dei buffer di memoria: http://www.postgresql.org/docs/9.1/static/runtime-config-resource.html
Se si gioca con work_mem vedrete la differenza nel comportamento query.

Tuttavia, l'utilizzo del join nella sottoquery è un modo molto migliore per velocizzare la query, poiché si limita il numero delle righe alla sorgente stessa, semplicemente selezionando le prime righe XYZ e quindi eseguendo i controlli.

Problemi correlati