Thread
-
Optimizer oddness, possibly compounded in 8.1
Philip Warner <pjw@rhyme.com.au> — 2005-12-02T14:55:09Z
The optimizer seems to want to use sequential scans on inherited tables when crossed with another table, as the following seems to demonstrate: Create Table base(f1 bigserial); create table inh1(f2 bigint) inherits (base); create table inh2(f2 bigint) inherits (base); create table inh3(f2 bigint) inherits (base); create table inh4(f2 bigint) inherits (base); insert into inh1(f2) values(1); insert into inh1(f2) select f2 from inh1; insert into inh1(f2) select f2 from inh1; insert into inh1(f2) select f2 from inh1; insert into inh1(f2) select f2 from inh1; insert into inh1(f2) select f2 from inh1; insert into inh1(f2) select f2 from inh1; insert into inh1(f2) select f2 from inh1; insert into inh1(f2) select f2 from inh1; insert into inh1(f2) select f2 from inh1; insert into inh1(f2) select f2 from inh1; insert into inh1(f2) select f2 from inh1; insert into inh1(f2) select f2 from inh1; insert into inh1(f2) select f2 from inh1; insert into inh1(f2) select f2 from inh1; insert into inh1(f2) select f2 from inh1; insert into inh1(f2) select f2 from inh1; create unique index base_f1 on base(f1); create unique index inh1_f1 on inh1(f1); create unique index inh2_f1 on inh2(f1); create unique index inh3_f1 on inh3(f1); create unique index inh4_f1 on inh4(f1); vacuum analyze base; vacuum analyze inh1; vacuum analyze inh2; vacuum analyze inh3; vacuum analyze inh4; create table t2(f1 bigint); insert into t2 values(1); insert into t2 values(2); insert into t2 values(128); insert into t2 values(32768); explain analyze select * from t2,base where base.f1=t2.f1; gives: Hash Join (cost=1.05..1546.04 rows=150 width=16) (actual time=0.433..436.791 rows=4 loops=1) Hash Cond: ("outer".f1 = "inner".f1) -> Append (cost=0.00..1181.66 rows=72366 width=8) (actual time=0.279..331.698 rows=65536 loops=1) -> Seq Scan on base (cost=0.00..29.40 rows=1940 width=8) (actual time=0.002..0.002 rows=0 loops=1) -> Seq Scan on inh1 base (cost=0.00..1073.36 rows=65536 width=8) (actual time=0.273..148.326 rows=65536 loops=1) -> Seq Scan on inh2 base (cost=0.00..26.30 rows=1630 width=8) (actual time=0.002..0.002 rows=0 loops=1) -> Seq Scan on inh3 base (cost=0.00..26.30 rows=1630 width=8) (actual time=0.003..0.003 rows=0 loops=1) -> Seq Scan on inh4 base (cost=0.00..26.30 rows=1630 width=8) (actual time=0.002..0.002 rows=0 loops=1) -> Hash (cost=1.04..1.04 rows=4 width=8) (actual time=0.132..0.132 rows=0 loops=1) -> Seq Scan on t2 (cost=0.00..1.04 rows=4 width=8) (actual time=0.111..0.119 rows=4 loops=1) Total runtime: 436.880 ms unwrapping the query into a series of UNIONS on the child tables reduces the run time by a factor of several hundred under PG8.0: explain analyze select z.f1 from t2,only base z where z.f1=t2.f1 UNION ALL select z.f1 from t2,inh1 z where z.f1=t2.f1 UNION ALL select z.f1 from t2,inh2 z where z.f1=t2.f1 UNION ALL select z.f1 from t2,inh3 z where z.f1=t2.f1 UNION ALL select z.f1 from t2,inh4 z where z.f1=t2.f1 Append (cost=0.00..94.87 rows=20 width=8) (actual time=0.184..0.485 rows=4 loops=1) -> Subquery Scan "*SELECT* 1" (cost=0.00..20.42 rows=4 width=8) (actual time=0.096..0.096 rows=0 loops=1) -> Nested Loop (cost=0.00..20.38 rows=4 width=8) (actual time=0.093..0.093 rows=0 loops=1) -> Seq Scan on t2 (cost=0.00..1.04 rows=4 width=8) (actual time=0.033..0.043 rows=4 loops=1) -> Index Scan using base_f1 on base z (cost=0.00..4.82 rows=1 width=8) (actual time=0.008..0.008 rows=0 loops=4) Index Cond: (z.f1 = "outer".f1) -> Subquery Scan "*SELECT* 2" (cost=0.00..13.18 rows=4 width=8) (actual time=0.084..0.194 rows=4 loops=1) -> Nested Loop (cost=0.00..13.14 rows=4 width=8) (actual time=0.081..0.178 rows=4 loops=1) -> Seq Scan on t2 (cost=0.00..1.04 rows=4 width=8) (actual time=0.002..0.012 rows=4 loops=1) -> Index Scan using inh1_f1 on inh1 z (cost=0.00..3.01 rows=1 width=8) (actual time=0.031..0.033 rows=1 loops=4) Index Cond: (z.f1 = "outer".f1) -> Subquery Scan "*SELECT* 3" (cost=0.00..20.42 rows=4 width=8) (actual time=0.061..0.061 rows=0 loops=1) -> Nested Loop (cost=0.00..20.38 rows=4 width=8) (actual time=0.057..0.057 rows=0 loops=1) -> Seq Scan on t2 (cost=0.00..1.04 rows=4 width=8) (actual time=0.003..0.011 rows=4 loops=1) -> Index Scan using inh2_f1 on inh2 z (cost=0.00..4.82 rows=1 width=8) (actual time=0.007..0.007 rows=0 loops=4) Index Cond: (z.f1 = "outer".f1) -> Subquery Scan "*SELECT* 4" (cost=0.00..20.42 rows=4 width=8) (actual time=0.058..0.058 rows=0 loops=1) -> Nested Loop (cost=0.00..20.38 rows=4 width=8) (actual time=0.055..0.055 rows=0 loops=1) -> Seq Scan on t2 (cost=0.00..1.04 rows=4 width=8) (actual time=0.002..0.011 rows=4 loops=1) -> Index Scan using inh3_f1 on inh3 z (cost=0.00..4.82 rows=1 width=8) (actual time=0.007..0.007 rows=0 loops=4) Index Cond: (z.f1 = "outer".f1) -> Subquery Scan "*SELECT* 5" (cost=0.00..20.42 rows=4 width=8) (actual time=0.058..0.058 rows=0 loops=1) -> Nested Loop (cost=0.00..20.38 rows=4 width=8) (actual time=0.054..0.054 rows=0 loops=1) -> Seq Scan on t2 (cost=0.00..1.04 rows=4 width=8) (actual time=0.003..0.012 rows=4 loops=1) -> Index Scan using inh4_f1 on inh4 z (cost=0.00..4.82 rows=1 width=8) (actual time=0.007..0.007 rows=0 loops=4) Index Cond: (z.f1 = "outer".f1) Total runtime: 0.643 ms Under 8.1, this unwrapping produces only a 4 times performance improvement:, and a different plan: Append (cost=34.25..2124.98 rows=9703 width=8) (actual time=0.386..249.311 rows=4 loops=1) -> Subquery Scan "*SELECT* 1" (cost=34.25..117.00 rows=1940 width=8) (actual time=0.035..0.035 rows=0 loops=1) -> Hash Join (cost=34.25..97.60 rows=1940 width=8) (actual time=0.027..0.027 rows=0 loops=1) Hash Cond: ("outer".f1 = "inner".f1) -> Seq Scan on t2 (cost=0.00..29.40 rows=1940 width=8) (never executed) -> Hash (cost=29.40..29.40 rows=1940 width=8) (actual time=0.011..0.011 rows=0 loops=1) -> Seq Scan on base z (cost=0.00..29.40 rows=1940 width=8) (actual time=0.005..0.005 rows=0 loops=1) -> Subquery Scan "*SELECT* 2" (cost=135.34..1668.58 rows=1940 width=8) (actual time=0.303..249.097 rows=4 loops=1) -> Merge Join (cost=135.34..1649.18 rows=1940 width=8) (actual time=0.296..249.063 rows=4 loops=1) Merge Cond: ("outer".f1 = "inner".f1) -> Index Scan using inh1_f1 on inh1 z (cost=0.00..1320.90 rows=65536 width=8) (actual time=0.179..133.717 rows=32769 loops=1) -> Sort (cost=135.34..140.19 rows=1940 width=8) (actual time=0.099..0.111 rows=4 loops=1) Sort Key: t2.f1 -> Seq Scan on t2 (cost=0.00..29.40 rows=1940 width=8) (actual time=0.007..0.025 rows=4 loops=1) -> Subquery Scan "*SELECT* 3" (cost=30.38..113.14 rows=1941 width=8) (actual time=0.042..0.042 rows=0 loops=1) -> Hash Join (cost=30.38..93.73 rows=1941 width=8) (actual time=0.035..0.035 rows=0 loops=1) Hash Cond: ("outer".f1 = "inner".f1) -> Seq Scan on t2 (cost=0.00..29.40 rows=1940 width=8) (never executed) -> Hash (cost=26.30..26.30 rows=1630 width=8) (actual time=0.012..0.012 rows=0 loops=1) -> Seq Scan on inh2 z (cost=0.00..26.30 rows=1630 width=8) (actual time=0.005..0.005 rows=0 loops=1) -> Subquery Scan "*SELECT* 4" (cost=30.38..113.14 rows=1941 width=8) (actual time=0.028..0.028 rows=0 loops=1) -> Hash Join (cost=30.38..93.73 rows=1941 width=8) (actual time=0.021..0.021 rows=0 loops=1) Hash Cond: ("outer".f1 = "inner".f1) -> Seq Scan on t2 (cost=0.00..29.40 rows=1940 width=8) (never executed) -> Hash (cost=26.30..26.30 rows=1630 width=8) (actual time=0.010..0.010 rows=0 loops=1) -> Seq Scan on inh3 z (cost=0.00..26.30 rows=1630 width=8) (actual time=0.004..0.004 rows=0 loops=1) -> Subquery Scan "*SELECT* 5" (cost=30.38..113.14 rows=1941 width=8) (actual time=0.026..0.026 rows=0 loops=1) -> Hash Join (cost=30.38..93.73 rows=1941 width=8) (actual time=0.019..0.019 rows=0 loops=1) Hash Cond: ("outer".f1 = "inner".f1) -> Seq Scan on t2 (cost=0.00..29.40 rows=1940 width=8) (never executed) -> Hash (cost=26.30..26.30 rows=1630 width=8) (actual time=0.010..0.010 rows=0 loops=1) -> Seq Scan on inh4 z (cost=0.00..26.30 rows=1630 width=8) (actual time=0.004..0.004 rows=0 loops=1) Total runtime: 249.522 ms (note 8.1 was installed on a different machine with more load, so the original query took > 1 sec). Ideally, both versions should know enough to use indexes in inherited tables. Is there anything that I am missing here, or that I can do to reduce the increase under 8.1? Ideally, the planner/optimizer should be unwrapping the inherited tables, I think. To add insult to injury, ENABLE_SEQSCAN has no effect. -
Re: Optimizer oddness, possibly compounded in 8.1
Tom Lane <tgl@sss.pgh.pa.us> — 2005-12-02T15:42:48Z
Philip Warner <pjw@rhyme.com.au> writes: > The optimizer seems to want to use sequential scans on inherited tables > when crossed with another table, as the following seems to demonstrate: Is it intentional that your test case omits an analyze on t2? Coz when I add that, I get the same plan you show for 8.0. Without the knowledge that t2 is small, that plan is not a good choice. (The larger point that joins of inheritance unions aren't well-planned is true, but it's always been true...) regards, tom lane
-
Re: Optimizer oddness, possibly compounded in 8.1
Philip Warner <pjw@rhyme.com.au> — 2005-12-03T00:35:04Z
>Is it intentional that your test case omits an analyze on t2? > No; my mistake. >(The larger point that joins of inheritance unions aren't well-planned >is true, but it's always been true...) It also seems to have a probkem with unions in views. Is there anything that can be done about this -- workarounds etc? Any plans to address it? We've got a couple of places where it's beginning to bite us due to growth of tables.
-
Re: Optimizer oddness, possibly compounded in 8.1
Tom Lane <tgl@sss.pgh.pa.us> — 2005-12-03T00:43:24Z
Philip Warner <pjw@rhyme.com.au> writes: >> (The larger point that joins of inheritance unions aren't well-planned >> is true, but it's always been true...) > It also seems to have a probkem with unions in views. > Is there anything that can be done about this -- workarounds etc? Any > plans to address it? We've got a couple of places where it's beginning > to bite us due to growth of tables. It's something that's on the ever-growing TODO list ... I dunno if anyone has any near-term plans to work on it. It'd definitely be nice to teach the planner to do joins-over-unions well, and then make inheritance just invoke that behavior instead of being a crocky special case. regards, tom lane
-
Re: Optimizer oddness, possibly compounded in 8.1
Philip Warner <pjw@rhyme.com.au> — 2005-12-03T06:10:22Z
Tom Lane wrote: >It's something that's on the ever-growing TODO list ... I dunno if >anyone has any near-term plans to work on it. It'd definitely be >nice to teach the planner to do joins-over-unions well, and then >make inheritance just invoke that behavior instead of being a crocky >special case. > > Sounds good; currently if you use the polymorphism of inherited tables, and happen to cross 2 such tables, you get O(n^2) performance.
-
Re: Optimizer oddness, possibly compounded in 8.1
Simon Riggs <simon@2ndquadrant.com> — 2005-12-03T09:21:37Z
On Fri, 2005-12-02 at 19:43 -0500, Tom Lane wrote: > Philip Warner <pjw@rhyme.com.au> writes: > >> (The larger point that joins of inheritance unions aren't well-planned > >> is true, but it's always been true...) > > > It also seems to have a probkem with unions in views. > > > Is there anything that can be done about this -- workarounds etc? Any > > plans to address it? We've got a couple of places where it's beginning > > to bite us due to growth of tables. > > It's something that's on the ever-growing TODO list ... I dunno if > anyone has any near-term plans to work on it. It'd definitely be > nice to teach the planner to do joins-over-unions well, and then > make inheritance just invoke that behavior instead of being a crocky > special case. There's a number of things that can be pushed down over a union set, in certain circumstances. sorts, GROUPs, min/max/limit, joins etc.. so I've been mulling over a generic push-down mechanism to avoid lots of special cases emerging. Joins to a union set are also an interesting case. First off, I think we need to do some more work on partitioning so that some knowledge about the union set is understood by the optimizer. At the moment there is no concept of partition key, so its hard to spot when two union sets have the same key to allow pushdown. I hope to work on some of that in the 8.2 timebox, but I suspect this is a multi-year mission. Best Regards, Simon Riggs
-
Re: Optimizer oddness, possibly compounded in 8.1
Philip Warner <pjw@rhyme.com.au> — 2005-12-03T11:06:40Z
>There's a number of things that can be pushed down over a union set, in >certain circumstances. > FWIW, you should also be able to push the unions up.
-
Re: Optimizer oddness, possibly compounded in 8.1
Hannu Krosing <hannu@skype.net> — 2005-12-06T14:12:15Z
Ühel kenal päeval, L, 2005-12-03 kell 09:21, kirjutas Simon Riggs: > First off, I think we need to do some more work on partitioning so that > some knowledge about the union set is understood by the optimizer. At > the moment there is no concept of partition key, so its hard to spot > when two union sets have the same key to allow pushdown. One of the easier cases would be non-overlapping (exclusive) constraints on union subtables on the joined column. This could serve as a "partition key", or in case of many nonoverlapping columns (ex.: table is partitioned by date and region), as many partition keys. ------------- Hannu
-
Re: Optimizer oddness, possibly compounded in 8.1
Simon Riggs <simon@2ndquadrant.com> — 2005-12-06T18:32:53Z
On Tue, 2005-12-06 at 16:12 +0200, Hannu Krosing wrote: > Ühel kenal päeval, L, 2005-12-03 kell 09:21, kirjutas Simon Riggs: > > > First off, I think we need to do some more work on partitioning so that > > some knowledge about the union set is understood by the optimizer. At > > the moment there is no concept of partition key, so its hard to spot > > when two union sets have the same key to allow pushdown. > > One of the easier cases would be non-overlapping (exclusive) constraints > on union subtables on the joined column. > > This could serve as a "partition key", or in case of many nonoverlapping > columns (ex.: table is partitioned by date and region), as many > partition keys. Yes, thats my planned direction. Best Regards, Simon Riggs
-
Re: Optimizer oddness, possibly compounded in 8.1
Christopher Kings-Lynne <chriskl@familyhealth.com.au> — 2005-12-07T01:46:57Z
>>One of the easier cases would be non-overlapping (exclusive) constraints >>on union subtables on the joined column. >> >>This could serve as a "partition key", or in case of many nonoverlapping >>columns (ex.: table is partitioned by date and region), as many >>partition keys. > > > Yes, thats my planned direction. In case you didn't know btw, MySQL 5.1 is out with rather extensive table partition support. So get coding :D Chris
-
Re: Optimizer oddness, possibly compounded in 8.1
Michael Glaesemann <grzm@myrealbox.com> — 2005-12-07T01:50:16Z
On Dec 7, 2005, at 10:46 , Christopher Kings-Lynne wrote: > In case you didn't know btw, MySQL 5.1 is out with rather extensive > table partition support. So get coding :D You do mean MySQL 5.1 alpha is out, right? Michael Glaesemann grzm myrealbox com