Hi -hackers,
While testing RC2 on the new servers of one of our customers, I found
a query really slow on the new server which is quite fast on the old
box currently in production (production is 8.1 at the moment).
If I set enable_nestloop to off, the query is fast (the plan is
different from the 8.1 plan though).
I attached:
- the plan with regular configuration;
- the plan after disabling nested loops;
- the plan obtained with 8.1 on the current production box;
- the relevant configuration and schema of the concerned tables.
The plans are really too different to find a narrower test case so
it's the real test case.
Feel free to ask any additional information or tests.
Regards,
--
Guillaume
cityvox_prod=# select version();
version
-----------------------------------------------------------------------------------------------------------
PostgreSQL 8.3RC2 on x86_64-redhat-linux-gnu, compiled by GCC gcc (GCC) 4.1.2
20070626 (Red Hat 4.1.2-14)
(1 row)
cityvox_prod=# show shared_buffers;
shared_buffers
----------------
2GB
(1 row)
cityvox_prod=# show work_mem;
work_mem
----------
32MB
(1 row)
cityvox_prod=# show effective_cache_size;
effective_cache_size
----------------------
5GB
(1 row)
cityvox_prod=# show lc_collate;
lc_collate
-------------
fr_FR.UTF-8
(1 row)
cityvox_prod=# show random_page_cost ;
random_page_cost
------------------
2
(1 row)
(same result with a random page cost of 4)
cityvox_prod=# \d association
Table "cityvox.association"
Column | Type |
Modifiers
---------------------+-----------------------------+-----------------------------------------------------------------------
numasso | integer | not null default
nextval(('seq_association_numasso'::text)::regclass)
nomasso | character varying(144) |
nomassoofficiel | character varying(144) | not null
mots_cleasso | character varying(150) |
adremailasso | character varying(200) |
adrurlsitepersoasso | character varying(400) |
adresseasso | character varying(200) |
codepostalasso | character varying(7) |
villeasso | character varying(40) |
codepaysasso | character varying(3) |
dcreaasso | timestamp without time zone | not null default now()
ddermodifasso | timestamp without time zone | not null default now()
nbrclicssiteweb | integer | default 0
codequarasso | character varying(5) | not null
nbradherents | integer | not null default 0
loginmodif | character varying(20) | not null default
'Association'::character varying
logincrea | character varying(20) | not null default
'Association'::character varying
adresseasso2 | character varying(200) |
villepostale | character varying(40) |
codeact | character varying(3) |
wgslat | numeric(11,8) |
wgslon | numeric(11,8) |
vilsup | character varying(100) |
fax | character varying(12) |
telephone | character varying(12) |
dderactivite | timestamp without time zone | not null default now()
assomaj | integer | not null default 0
Indexes:
"pk_association" PRIMARY KEY, btree (numasso)
Foreign-key constraints:
"fk_association_codepays" FOREIGN KEY (codepaysasso) REFERENCES
pays(codepays)
"fk_association_codequar" FOREIGN KEY (codequarasso) REFERENCES
quartier(codequar)
"fk_association_validation" FOREIGN KEY (codeact) REFERENCES
statuttraitement(codestatutttmt)
cityvox_prod=# \d assovil
Table "cityvox.assovil"
Column | Type | Modifiers
---------+----------------------+-----------
numasso | integer | not null
codevil | character varying(3) | not null
Indexes:
"pk_assovil" PRIMARY KEY, btree (numasso, codevil)
Foreign-key constraints:
"fk_assovil_codevil" FOREIGN KEY (codevil) REFERENCES vilsite(codevil) ON
DELETE CASCADE
"fk_assovil_numasso" FOREIGN KEY (numasso) REFERENCES association(numasso)
ON DELETE CASCADE
cityvox_prod=# \d evelieu
Table "cityvox.evelieu"
Column | Type | Modifiers
-----------------+-----------------------------+--------------------
numlieu | integer | not null
numeve | integer | not null
ddebevelieu | timestamp without time zone | not null
dfinevelieu | timestamp without time zone | not null
logincrea | character varying(32) | not null
loginmodif | character varying(32) | not null
dcreaevelieu | timestamp without time zone | not null
ddermajevelieu | timestamp without time zone | not null
inforeservation | character varying(200) |
codestatut | character varying(2) | not null
prolongation | integer | not null default 0
nummanif | integer |
flagphoto | integer | not null default 0
codestatutresa | integer | not null default 0
codemodelivr | character varying(1) |
codetypebillets | character varying(1) |
pushbilletterie | integer | not null default 9
partenaire_cit | integer | not null default 0
numasso | integer |
Indexes:
"pk_evelieu" PRIMARY KEY, btree (numlieu, numeve)
"idx_evelieu_ddebevelieu_trunc" btree (date_trunc('day'::text, ddebevelieu))
"idx_evelieu_dfinevelieu" btree (dfinevelieu)
"idx_evelieu_dfinevelieu_trunc" btree (date_trunc('day'::text, dfinevelieu))
"idx_evelieu_numeve" btree (numeve)
"idx_evelieu_numeve_numlieu_ddebevelieu_dfinevelieu" btree (numeve,
numlieu, ddebevelieu, dfinevelieu)
"idx_evelieu_numeve_numlieu_dfinevelieu" btree (numeve, numlieu,
dfinevelieu)
"idx_evelieu_numeve_nummanif" btree (numeve, nummanif)
"idx_evelieu_numlieu_ddermajevelieu" btree (numlieu, ddermajevelieu)
"idx_on_evelieu_numeve_numlieu_dfinevelieu" btree (numeve, numlieu,
date_trunc('day'::text, dfinevelieu))
Foreign-key constraints:
"fk_evelieu_numasso" FOREIGN KEY (numasso) REFERENCES association(numasso)
"fk_evelieu_ref_codemodelivr" FOREIGN KEY (codemodelivr) REFERENCES
modelivraison(codemodelivr) ON DELETE CASCADE
"fk_evelieu_ref_codetypebillets" FOREIGN KEY (codetypebillets) REFERENCES
typebillets(codetypebillets) ON DELETE CASCADE
"fk_evelieu_ref_eve" FOREIGN KEY (numeve) REFERENCES evenement(numeve) ON
DELETE CASCADE
"fk_evelieu_ref_lieu" FOREIGN KEY (numlieu) REFERENCES lieu(numlieu) ON
DELETE CASCADE
"fk_evelieu_ref_nummanif" FOREIGN KEY (nummanif) REFERENCES
evenement(numeve) ON DELETE CASCADE
"fk_evelieu_ref_statut" FOREIGN KEY (codestatut) REFERENCES
statut(codestatut) ON DELETE CASCADE
"fk_evelieu_statutresa" FOREIGN KEY (codestatutresa) REFERENCES
statutresa(codestatutresa) ON DELETE CASCADE
cityvox_prod=# \d lieu
Table "cityvox.lieu"
Column | Type | Modifiers
----------------------+-----------------------------+------------------------------
numlieu | integer | not null
codequar | character varying(5) | not null
a lot of other fields...
Indexes:
"pk_lieu" PRIMARY KEY, btree (numlieu)
"idx_lieu_identifianturl" UNIQUE, btree (identifianturl)
"idx_lieu_codepostallieu" btree (codepostallieu)
"idx_lieu_codequar_nomlieu_upper_like" btree (codequar,
upper(nomlieu::text) varchar_pattern_ops)
"idx_lieu_codequar_notmoylieu_flagphoto_interditalaune" btree (codequar,
notmoylieu, flagphoto, interditalaune)
"idx_lieu_coordonnees_terrestres" gist (ll_to_earth(wgslat::double
precision, wgslon::double precision))
"idx_lieu_dfinvalidlieu" btree (dfinvalidlieu)
"idx_lieu_libvilpostalelieu" btree (libvilpostalelieu)
"idx_lieu_nomlieu_upper_like" btree (upper(nomlieu::text)
varchar_pattern_ops)
"idx_lieu_numcamerapress" btree (numcamerapress)
"idx_lieu_numlieu_codequar_dfinvalidlieu" btree (numlieu, codequar,
dfinvalidlieu)
"idx_lieu_presenceplus" btree (presenceplus) WHERE presenceplus = 1
"lieu_i_codequar" btree (codequar)
"lieu_i_nomlieu" btree (nomlieu)
Foreign-key constraints:
"fk_lieu_est_situe_quartier" FOREIGN KEY (codequar) REFERENCES
quartier(codequar)
"fk_lieu_ref_sourceinfo" FOREIGN KEY (codesourceinfo) REFERENCES
sourceinfo(codesourceinfo)
"fk_lieu_tyvoielie_tyvoie" FOREIGN KEY (codetyvoie) REFERENCES
tyvoie(codetyvoie)
cityvox_prod=# \d vilquartier
Table "cityvox.vilquartier"
Column | Type | Modifiers
----------------+------------------------+-----------------------------------------
codevil | character varying(3) | not null
codequar | character varying(5) | not null
liblong | character varying(100) | not null
flagintramuros | character varying(1) | not null default 'O'::character
varying
libcourt | character varying(100) | not null
Indexes:
"pk_vilquartier" PRIMARY KEY, btree (codequar, codevil)
"idx_vilquartier_codevil" btree (codevil)
"vilquartier_i_codequar" btree (codequar)
Foreign-key constraints:
"fk_vilqtier_ref_quartier" FOREIGN KEY (codequar) REFERENCES
quartier(codequar) ON DELETE CASCADE
"fk_vilqtier_ref_vilsite" FOREIGN KEY (codevil) REFERENCES vilsite(codevil)
ON DELETE CASCADE
cityvox_prod=# EXPLAIN ANALYZE SELECT a.numasso, a.nomasso, a.nomassoofficiel,
el.numeve, el.numlieu, vq.codequar, toTimestamp(ddebevelieu) as debutevelieu,
toTimestamp(dfinevelieu) as finevelieu FROM association a, evelieu el, assovil
av, lieu l, vilquartier vq WHERE 1=1 AND l.codequar = vq.codequar AND l.numlieu
= el.numlieu AND vq.codevil = av.codevil AND a.numasso = el.numasso AND
a.numasso = av.numasso AND a.codeact = 'V' AND av.codevil = 'LYO' AND
date_trunc('day', el.dfinevelieu) >= date_trunc('day', now()) ORDER BY
el.numeve ASC LIMIT 5;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=3169.91..3169.91 rows=1 width=68) (actual time=8106.727..8106.730
rows=1 loops=1)
-> Sort (cost=3169.91..3169.91 rows=1 width=68) (actual
time=8106.725..8106.726 rows=1 loops=1)
Sort Key: el.numeve
Sort Method: quicksort Memory: 25kB
-> Nested Loop (cost=7.55..3169.90 rows=1 width=68) (actual
time=5138.594..8106.706 rows=1 loops=1)
Join Filter: ((vq.codequar)::text = (l.codequar)::text)
-> Merge Join (cost=7.55..2905.50 rows=65 width=68) (actual
time=5138.556..8106.465 rows=36 loops=1)
Merge Cond: (el.numasso = a.numasso)
-> Nested Loop (cost=0.00..254537.64 rows=90 width=37)
(actual time=5137.405..8104.863 rows=36 loops=1)
-> Nested Loop (cost=0.00..254387.29 rows=5
width=36) (actual time=5137.375..8104.719 rows=2 loops=1)
Join Filter: (el.numasso = av.numasso)
-> Index Scan using pk_assovil on assovil av
(cost=0.00..32.01 rows=38 width=8) (actual time=0.028..0.238 rows=38 loops=1)
Index Cond: ((codevil)::text =
'LYO'::text)
-> Seq Scan on evelieu el
(cost=0.00..5978.46 rows=57208 width=28) (actual time=0.010..197.039 rows=28019
loops=38)
Filter: (date_trunc('day'::text,
el.dfinevelieu) >= date_trunc('day'::text, now()))
-> Index Scan using idx_vilquartier_codevil on
vilquartier vq (cost=0.00..29.89 rows=18 width=9) (actual time=0.025..0.045
rows=18 loops=2)
Index Cond: ((vq.codevil)::text = 'LYO'::text)
-> Index Scan using pk_association on association a
(cost=0.00..75.50 rows=717 width=39) (actual time=0.017..1.115 rows=727 loops=1)
Filter: ((a.codeact)::text = 'V'::text)
-> Index Scan using pk_lieu on lieu l (cost=0.00..4.05 rows=1
width=9) (actual time=0.003..0.004 rows=1 loops=36)
Index Cond: (l.numlieu = el.numlieu)
Total runtime: 8106.852 ms
cityvox_prod=# set enable_nestloop = off;
SET
cityvox_prod=# EXPLAIN ANALYZE SELECT a.numasso, a.nomasso, a.nomassoofficiel,
el.numeve, el.numlieu, vq.codequar, toTimestamp(ddebevelieu) as debutevelieu,
toTimestamp(dfinevelieu) as finevelieu FROM association a, evelieu el, assovil
av, lieu l, vilquartier vq WHERE 1=1 AND l.codequar = vq.codequar AND l.numlieu
= el.numlieu AND vq.codevil = av.codevil AND a.numasso = el.numasso AND
a.numasso = av.numasso AND a.codeact = 'V' AND av.codevil = 'LYO' AND
date_trunc('day', el.dfinevelieu) >= date_trunc('day', now()) ORDER BY
el.numeve ASC LIMIT 5;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=11724.96..11724.97 rows=1 width=68) (actual time=209.723..209.726
rows=1 loops=1)
-> Sort (cost=11724.96..11724.97 rows=1 width=68) (actual
time=209.721..209.722 rows=1 loops=1)
Sort Key: el.numeve
Sort Method: quicksort Memory: 25kB
-> Hash Join (cost=4760.99..11724.95 rows=1 width=68) (actual
time=182.555..209.699 rows=1 loops=1)
Hash Cond: ((l.codequar)::text = (vq.codequar)::text)
-> Hash Join (cost=4740.63..11704.47 rows=4 width=72) (actual
time=71.275..209.553 rows=2 loops=1)
Hash Cond: (l.numlieu = el.numlieu)
-> Seq Scan on lieu l (cost=0.00..6481.40 rows=128640
width=9) (actual time=0.006..85.340 rows=128640 loops=1)
-> Hash (cost=4740.58..4740.58 rows=4 width=67) (actual
time=45.302..45.302 rows=2 loops=1)
-> Hash Join (cost=835.85..4740.58 rows=4
width=67) (actual time=20.648..45.296 rows=2 loops=1)
Hash Cond: (el.numasso = a.numasso)
-> Bitmap Heap Scan on evelieu el
(cost=759.63..4449.79 rows=57208 width=28) (actual time=8.854..27.657
rows=28019 loops=1)
Recheck Cond: (date_trunc('day'::text,
dfinevelieu) >= date_trunc('day'::text, now()))
-> Bitmap Index Scan on
idx_evelieu_dfinevelieu_trunc (cost=0.00..745.33 rows=57208 width=0) (actual
time=8.707..8.707 rows=28019 loops=1)
Index Cond:
(date_trunc('day'::text, dfinevelieu) >= date_trunc('day'::text, now()))
-> Hash (cost=75.84..75.84 rows=30 width=47)
(actual time=1.808..1.808 rows=26 loops=1)
-> Hash Join (cost=49.16..75.84
rows=30 width=47) (actual time=1.546..1.783 rows=26 loops=1)
Hash Cond: (av.numasso = a.numasso)
-> Seq Scan on assovil av
(cost=0.00..26.24 rows=38 width=8) (actual time=0.015..0.205 rows=38 loops=1)
Filter: ((codevil)::text =
'LYO'::text)
-> Hash (cost=40.20..40.20
rows=717 width=39) (actual time=1.519..1.519 rows=717 loops=1)
-> Seq Scan on association
a (cost=0.00..40.20 rows=717 width=39) (actual time=0.005..0.886 rows=717
loops=1)
Filter:
((codeact)::text = 'V'::text)
-> Hash (cost=20.14..20.14 rows=18 width=9) (actual
time=0.088..0.088 rows=18 loops=1)
-> Bitmap Heap Scan on vilquartier vq (cost=2.39..20.14
rows=18 width=9) (actual time=0.043..0.063 rows=18 loops=1)
Recheck Cond: ((codevil)::text = 'LYO'::text)
-> Bitmap Index Scan on idx_vilquartier_codevil
(cost=0.00..2.39 rows=18 width=0) (actual time=0.035..0.035 rows=18 loops=1)
Index Cond: ((codevil)::text = 'LYO'::text)
Total runtime: 209.839 ms
cityvox_prod=# EXPLAIN ANALYZE SELECT a.numasso, a.nomasso, a.nomassoofficiel,
el.numeve, el.numlieu, vq.codequar, toTimestamp(ddebevelieu) as debutevelieu,
toTimestamp(dfinevelieu) as finevelieu FROM association a, evelieu el, assovil
av, lieu l, vilquartier vq WHERE 1=1 AND l.codequar = vq.codequar AND l.numlieu
= el.numlieu AND vq.codevil = av.codevil AND a.numasso = el.numasso AND
a.numasso = av.numasso AND a.codeact = 'V' AND av.codevil = 'LYO' AND
date_trunc('day', el.dfinevelieu) >= date_trunc('day', now()) ORDER BY
el.numeve ASC LIMIT 5;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=3964.90..3964.91 rows=1 width=77) (actual time=305.762..305.775
rows=1 loops=1)
-> Sort (cost=3964.90..3964.91 rows=1 width=77) (actual
time=305.752..305.757 rows=1 loops=1)
Sort Key: el.numeve
-> Nested Loop (cost=332.95..3964.89 rows=1 width=77) (actual
time=128.550..305.711 rows=1 loops=1)
-> Nested Loop (cost=332.95..3960.88 rows=1 width=84) (actual
time=128.454..305.557 rows=2 loops=1)
-> Nested Loop (cost=332.95..3956.85 rows=1 width=76)
(actual time=128.409..305.443 rows=2 loops=1)
-> Hash Join (cost=332.95..3953.41 rows=1
width=73) (actual time=88.687..303.937 rows=66 loops=1)
Hash Cond: ("outer".numasso = "inner".numasso)
-> Bitmap Heap Scan on evelieu el
(cost=282.57..3757.93 rows=29018 width=28) (actual time=44.335..178.776
rows=28512 loops=1)
Recheck Cond: (date_trunc('day'::text,
dfinevelieu) >= date_trunc('day'::text, now()))
-> Bitmap Index Scan on
idx_evelieu_dfinevelieu_trunc (cost=0.00..282.57 rows=29018 width=0) (actual
time=43.811..43.811 rows=28512 loops=1)
Index Cond:
(date_trunc('day'::text, dfinevelieu) >= date_trunc('day'::text, now()))
-> Hash (cost=48.54..48.54 rows=738
width=45) (actual time=9.575..9.575 rows=718 loops=1)
-> Seq Scan on association a
(cost=0.00..48.54 rows=738 width=45) (actual time=0.015..4.835 rows=718 loops=1)
Filter: ((codeact)::text =
'V'::text)
-> Index Scan using pk_assovil on assovil av
(cost=0.00..3.43 rows=1 width=11) (actual time=0.014..0.014 rows=0 loops=66)
Index Cond: (("outer".numasso = av.numasso)
AND ((av.codevil)::text = 'LYO'::text))
-> Index Scan using pk_lieu on lieu l (cost=0.00..4.01
rows=1 width=12) (actual time=0.026..0.031 rows=1 loops=2)
Index Cond: (l.numlieu = "outer".numlieu)
-> Index Scan using pk_vilquartier on vilquartier vq
(cost=0.00..3.99 rows=1 width=15) (actual time=0.032..0.035 rows=0 loops=2)
Index Cond: ((("outer".codequar)::text =
(vq.codequar)::text) AND ('LYO'::text = (vq.codevil)::text))
Total runtime: 306.182 ms
(22 rows)
---------------------------(end of broadcast)---------------------------
TIP 7: You can help support the PostgreSQL project by donating at
http://www.postgresql.org/about/donate