Re: [postgresql-it] Problema performance query

  • From: "Ing. Claudio Rossi" <ing.claudiorossi@xxxxxxxxx>
  • To: postgresql-it@xxxxxxxxxxxxx
  • Date: Wed, 16 Apr 2008 22:36:18 +0200

Ciao, secondo me succede questo:

Nel primo caso usa l'algoritmo di Nested Loop per il join, che
generalmente e' il piu' scarso come performance, ma che ottiene buoni
risultati grazie all'indice sull'inner table (Index Scan using
idx_rilev on dettagliorilevamenti dr). Inoltre, da bravo query
optimizer, ti fa anche il push della selezione. Quindi la prima query
va veloce perche' e' ottimizzata al meglio.

La seconda query invece e' abbastanza chiara ma dovrai rispondere a
una domanda dopo per capire perche' scegli questo query plan. In
pratica nella seconda query lui sceglie il Merge Join che teoricamente
e' superiore nelle performance MA a una condizione: gli attributi su
cui fai il join devono essere preordinati o indicizzati, altrimenti lo
fa postgresql il sort, che ha un costo elevatissimo e che ti fa andare
peggio di un Nested Loop. E uno dei due non e' indicizzato. Ti faccio
il commento riga per riga:

  ->  Merge Join  (cost=1869.01..829123.45 rows=306454 width=0)
        Merge Cond: ("outer".id_rilev = "inner".id)

Sceglie il Merge Join vedendo la condizione "outer".id_rilev =
"inner".id che sarebbe r.id_rilev=r.id (a proposito, mi insospettisce
che qua l'outer table sia diventata dettagliorilevamenti mentre prima
era rilevamenti, controlla se hai scritto la query correttamente, ma
magari non vuol dire nulla).

        ->  Index Scan using idx_rilev on dettagliorilevamenti dr
(cost=0.00..767437.41 rows=22245028 width=4)

I due attributi del join devono essere indicizzati o ordinati. Per
dr.id_rilev non c'e' problema, c'e' un indice e usa quello.

        ->  Sort  (cost=1869.01..1876.54 rows=3015 width=8)
              Sort Key: r.id

ECCOLO QUA :) il problema. Non trova nessun indice su r.id (se e'
chiave primaria, non chiedermi perche' non e' indicizzato...), quindi
fa un sort, che e' cio' che fa schizzare il tempo di esecuzione.
Perche' manca l'indice? Devi dirmelo tu :)

              ->  Index Scan using idx_data on rilevamenti r
(cost=0.00..1694.77 rows=3015 width=8)
                    Index Cond: ((datain >= '2007-12-01
00:00:00'::timestamp without time zone) AND (datain <= '2007-12-12
00:00:00'::timestamp without time zone))

E qua fa la solita selezione.

Conclusioni: controlla quelle due cose che ti ho scritto (se la query
e' corretta e se c'e' l'indice su r.id). Se le risposte sono entrambe
positive, non so darti al momento soluzioni, pero' il planner nella
seconda query sceglie un'esecuzione molto piu' onerosa della prima per
via del sort. Spero sia stato compensibile, sono le 10 e mezza di sera
:)

ciao a tutti,

sto facendo esperimenti di performance con Postgres per eventualmente
portare un DB da MS SQL server a PostgreSQL.
Ho importato in Postgres le due tabelle più 'corpose':
'rilevamenti' da 220000 record circa e
'dettagliorilevamenti' da 22 milioni di record circa.

Quando eseguo la seguente query il tempo impiegato è accettabile (e
molto breve dal secondo run):

explain select count(*) as N
from rilevamenti r
       inner join dettagliorilevamenti dr on r.id=dr.id_rilev
where r.datain between '2007-12-01' and '2007-12-11'

Aggregate  (cost=821350.49..821350.50 rows=1 width=0)
  ->  Nested Loop  (cost=0.00..820653.98 rows=278604 width=0)
        ->  Index Scan using idx_data on rilevamenti r
(cost=0.00..1546.23 rows=2741 width=8)
              Index Cond: ((datain >= '2007-12-01 00:00:00'::timestamp
without time zone) AND (datain <= '2007-12-11 00:00:00'::timestamp
without time zone))
        ->  Index Scan using idx_rilev on dettagliorilevamenti dr
(cost=0.00..224.01 rows=5986 width=4)
              Index Cond: ("outer".id = dr.id_rilev)

se aggiungo un giorno nella query (come data finale chiedo '2007-12-12')
il tempo di esecuzione esplode (e non migliora nei run successivi) e il
query plan diventa:

Aggregate  (cost=829889.59..829889.60 rows=1 width=0)
  ->  Merge Join  (cost=1869.01..829123.45 rows=306454 width=0)
        Merge Cond: ("outer".id_rilev = "inner".id)
        ->  Index Scan using idx_rilev on dettagliorilevamenti dr
(cost=0.00..767437.41 rows=22245028 width=4)
        ->  Sort  (cost=1869.01..1876.54 rows=3015 width=8)
              Sort Key: r.id
              ->  Index Scan using idx_data on rilevamenti r
(cost=0.00..1694.77 rows=3015 width=8)
                    Index Cond: ((datain >= '2007-12-01
00:00:00'::timestamp without time zone) AND (datain <= '2007-12-12
00:00:00'::timestamp without time zone))

qualcuno potrebbe indicarmi quale strada potrei intraprendere per
cercare di risolvere il problema?

grazie e ciao
riki

Other related posts: