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