Thread: BUG #17650: For the sixth time, the clipping function in the 120 partition table planning stage fails
BUG #17650: For the sixth time, the clipping function in the 120 partition table planning stage fails
From
PG Bug reporting form
Date:
The following bug has been logged on the website: Bug reference: 17650 Logged by: dafoer Email address: dafoer_x@163.com PostgreSQL version: 14.0 Operating system: centos7.6 Description: The clipping function of partition table cannot be carried out normally in the planning stage. The extension protocol cannot be clipped in the sixth execution. When concurrency is high, lock contention is serious postgres=# prepare fun3(int, int) as select * from t_range where f1=$1 and f2 = $2 + 2; PREPARE Time: 0.439 ms postgres=# execute fun3(3486,201703); f1 | f2 | f3 | f4 ------+--------+------+---------------------------------- 3486 | 201705 | 3486 | ab4f2b5fd96ca65349119909c1eada2d (1 row) Time: 1.431 ms postgres=# postgres=# execute fun3(3486,201703); f1 | f2 | f3 | f4 ------+--------+------+---------------------------------- 3486 | 201705 | 3486 | ab4f2b5fd96ca65349119909c1eada2d (1 row) Time: 0.451 ms postgres=# execute fun3(3486,201703); f1 | f2 | f3 | f4 ------+--------+------+---------------------------------- 3486 | 201705 | 3486 | ab4f2b5fd96ca65349119909c1eada2d (1 row) Time: 0.430 ms postgres=# execute fun3(3486,201703); f1 | f2 | f3 | f4 ------+--------+------+---------------------------------- 3486 | 201705 | 3486 | ab4f2b5fd96ca65349119909c1eada2d (1 row) Time: 0.421 ms postgres=# execute fun3(3486,201703); f1 | f2 | f3 | f4 ------+--------+------+---------------------------------- 3486 | 201705 | 3486 | ab4f2b5fd96ca65349119909c1eada2d (1 row) Time: 0.416 ms postgres=# execute fun3(3486,201703); f1 | f2 | f3 | f4 ------+--------+------+---------------------------------- 3486 | 201705 | 3486 | ab4f2b5fd96ca65349119909c1eada2d (1 row) Time: 7.568 ms (-- It took too much time <<<<<<<<=======================) postgres=# execute fun3(3486,201703); f1 | f2 | f3 | f4 ------+--------+------+---------------------------------- 3486 | 201705 | 3486 | ab4f2b5fd96ca65349119909c1eada2d (1 row) Time: 0.450 ms postgres=# execute fun3(3486,201703); f1 | f2 | f3 | f4 ------+--------+------+---------------------------------- 3486 | 201705 | 3486 | ab4f2b5fd96ca65349119909c1eada2d (1 row) use cases: prepare fun3(int, int) as select * from t_range where f1=$1 and f2 = $2 + 2; execute fun3(3486,201703); -- create table create or replace function init_t_range_data(start_date int) returns void as $$ DECLARE i int; sql text; pd int; BEGIN pd := start_date; for i in 1..11 loop sql:=format('create table if not exists t_range_%s PARTITION OF t_range for values from (%s) to (%s);', pd, pd, pd+1); execute sql; raise notice '%',sql; sql:=format('insert into t_range(f1,f2,f3,f4) select t, %s, mod(t,10000), md5(t::varchar) from generate_series(1,100000) t;', pd); execute sql; raise notice '%',sql; sql:=format('create index if not exists t_range_%s_f3_idx on t_range_%s(f3);',pd,pd); execute sql; raise notice '%',sql; sql:=format('create index if not exists t_range_%s_f1_idx on t_range_%s(f1);',pd,pd); execute sql; raise notice '%',sql; pd:=pd+1; end loop; pd := start_date; sql:=format('create table if not exists t_range_%s PARTITION OF t_range for values from (%s) to (%s);', pd+11, pd+11, pd+100); execute sql; raise notice '%',sql; sql:=format('insert into t_range(f1,f2,f3,f4) select t, %s, mod(t,10000), md5(t::varchar) from generate_series(1,100000) t;', pd+11); execute sql; raise notice '%',sql; sql:=format('create index if not exists t_range_%s_f3_idx on t_range_%s(f3);',pd+11,pd+11); execute sql; raise notice '%',sql; sql:=format('create index if not exists t_range_%s_f1_idx on t_range_%s(f1);',pd+11,pd+11); execute sql; raise notice '%',sql; end; $$ language plpgsql; drop table if exists t_range cascade; create table t_range (f1 bigint,f2 int , f3 integer, f4 varchar(100) ) partition by range ( f2 ); select init_t_range_data(201701); create or replace function init_t_range_data(start_date int) returns void as $$ DECLARE i int; sql text; pd int; BEGIN pd := start_date; for i in 1..11 loop sql:=format('create table if not exists t_range_%s PARTITION OF t_range for values from (%s) to (%s);', pd, pd, pd+1); execute sql; raise notice '%',sql; --sql:=format('insert into t_range(f1,f2,f3,f4) select t, %s, mod(t,10000), md5(t::varchar) from generate_series(1,100000) t;', pd); --execute sql; --raise notice '%',sql; sql:=format('create index if not exists t_range_%s_f3_idx on t_range_%s(f3);',pd,pd); execute sql; raise notice '%',sql; sql:=format('create index if not exists t_range_%s_f1_idx on t_range_%s(f1);',pd,pd); execute sql; raise notice '%',sql; pd:=pd+1; end loop; pd := start_date; sql:=format('create table if not exists t_range_%s PARTITION OF t_range for values from (%s) to (%s);', pd+11, pd+11, pd+100); execute sql; raise notice '%',sql; --sql:=format('insert into t_range(f1,f2,f3,f4) select t, %s, mod(t,10000), md5(t::varchar) from generate_series(1,100000) t;', pd+11); --execute sql; --raise notice '%',sql; sql:=format('create index if not exists t_range_%s_f3_idx on t_range_%s(f3);',pd+11,pd+11); execute sql; raise notice '%',sql; sql:=format('create index if not exists t_range_%s_f1_idx on t_range_%s(f1);',pd+11,pd+11); execute sql; raise notice '%',sql; end; $$ language plpgsql; select init_t_range_data(201601); select init_t_range_data(201801); select init_t_range_data(201901); select init_t_range_data(202001); select init_t_range_data(202101); select init_t_range_data(202201); select init_t_range_data(202301); select init_t_range_data(202401); select init_t_range_data(202501); vacuum (analyze, verbose) t_range;
Re: BUG #17650: For the sixth time, the clipping function in the 120 partition table planning stage fails
From
Julien Rouhaud
Date:
Hi, On Tue, Oct 18, 2022 at 01:11:13PM +0000, PG Bug reporting form wrote: > The following bug has been logged on the website: > > Bug reference: 17650 > Logged by: dafoer > Email address: dafoer_x@163.com > PostgreSQL version: 14.0 Unrelated but you should definitely update to the latest minor version, currently 14.5 > Operating system: centos7.6 > Description: > > The clipping function of partition table cannot be carried out normally in > the planning stage. The extension protocol cannot be clipped in the sixth > execution. When concurrency is high, lock contention is serious I'm not sure I fully understand. Are you saying that partition pruning (1) doesn't happen after 6 execution of a prepared statement? If yes, it's not a bug but a known behavior of generic plans. You can dynamically set plan_cache_mode to force_custom_plan for the cases where generic plans are known to behave poorly. [1] https://www.postgresql.org/docs/current/ddl-partitioning.html#DDL-PARTITION-PRUNING
Re: BUG #17650: For the sixth time, the clipping function in the 120 partition table planning stage fails
From
Tom Lane
Date:
PG Bug reporting form <noreply@postgresql.org> writes: > The clipping function of partition table cannot be carried out normally in > the planning stage. This looks like normal behavior to me: the sixth iteration is where the plan cache will try to see if a generic plan would be smarter to use than a custom one. Unsurprisingly, for a table partitioned as heavily as this one, it takes a little while even to construct a generic plan. Then it'll decide "nope, we'll stick to custom planning" and the subsequent executions take the same amount of time as before. You could override that with "set plan_cache_mode = force_custom_plan". But TBH my advice is to use fewer partitions. There are always going to be edge cases where the system has to consider all the partitions. If you're allergic to spending even half a dozen msec in the planner, you need to set up your tables in a way that doesn't require so much time when that happens. regards, tom lane
Re: BUG #17650: For the sixth time, the clipping function in the 120 partition table planning stage fails
From
Andy Fan
Date:
On Tue, Oct 18, 2022 at 10:06 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
Then it'll decide "nope, we'll stick to custom
planning" and the subsequent executions take the same amount of
time as before.
I think we have known the cost model issue for any kind of run-time partition prune
(initial partition prune or execution partition prune), the issue is that we always cost
the partitions which have been pruned already. One of the side effects is that a generic
plan is nearly impossible to win, hence planning effort is always there. Do you think
we need to do anything for this? We can't forecast how many / which partitions
are pruned or left, but even we just improve the case where only 1 partition is left, we
improve the most common cases.
Best Regards
Andy Fan