Skip to content

Commit 58cc529

Browse files
andr-sokolovhanwei
authored andcommitted
Set join_collapse_limit default value to 13 (#1525)
The default value of join_collapse_limit was 20. When this value is set and the query contains about 20 joins (see added test), Postgres query optimizer cannot build a plan during hours and consumes a lot of memory, because the planner checks a lot of possible ways to join the tables. When join_collapse_limit is 8, the query plan is built in reasonable time.
1 parent 89d008f commit 58cc529

File tree

5 files changed

+125
-2
lines changed

5 files changed

+125
-2
lines changed

src/backend/utils/misc/guc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2290,7 +2290,7 @@ static struct config_int ConfigureNamesInt[] =
22902290
GUC_EXPLAIN
22912291
},
22922292
&join_collapse_limit,
2293-
20, 1, INT_MAX,
2293+
13, 1, INT_MAX,
22942294
NULL, NULL, NULL
22952295
},
22962296
{

src/backend/utils/misc/postgresql.conf.sample

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ max_prepared_transactions = 250 # can be 0 or more
434434
#cursor_tuple_fraction = 0.1 # range 0.0-1.0
435435

436436
#from_collapse_limit = 20
437-
#join_collapse_limit = 20 # 1 disables collapsing of explicit
437+
#join_collapse_limit = 13 # 1 disables collapsing of explicit
438438
# JOIN clauses
439439
#force_parallel_mode = off
440440
#jit = on # allow JIT compilation

src/test/regress/expected/bfv_joins.out

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4189,6 +4189,48 @@ INSERT INTO ext_stats_tbl VALUES('tC', true);
41894189
ANALYZE ext_stats_tbl;
41904190
explain SELECT 1 FROM ext_stats_tbl t11 FULL JOIN ext_stats_tbl t12 ON t12.c2;
41914191
ERROR: FULL JOIN is only supported with merge-joinable or hash-joinable join conditions
4192+
-- Check that Postgres Planner can build a plan with 20 joins in reasonable time
4193+
do $$
4194+
begin
4195+
for i in 1..20 loop
4196+
execute 'create table tj' || i || '(id int)';
4197+
end loop;
4198+
end
4199+
$$;
4200+
set optimizer to off;
4201+
select trunc(extract(epoch from now())) unix_time1 \gset
4202+
select *
4203+
from tj1
4204+
join tj2 on tj1.id = tj2.id
4205+
join tj3 on tj2.id = tj3.id
4206+
join tj4 on tj3.id = tj4.id
4207+
join tj5 on tj4.id = tj5.id
4208+
join tj6 on tj5.id = tj6.id
4209+
join tj7 on tj6.id = tj7.id
4210+
join tj8 on tj7.id = tj8.id
4211+
join tj9 on tj8.id = tj9.id
4212+
join tj10 on tj9.id = tj10.id
4213+
join tj11 on tj10.id = tj11.id
4214+
join tj12 on tj11.id = tj12.id
4215+
join tj13 on tj12.id = tj13.id
4216+
join tj14 on tj13.id = tj14.id
4217+
join tj15 on tj14.id = tj15.id
4218+
join tj16 on tj15.id = tj16.id
4219+
join tj17 on tj16.id = tj17.id
4220+
join tj18 on tj17.id = tj18.id
4221+
join tj19 on tj18.id = tj19.id
4222+
join tj20 on tj19.id = tj20.id;
4223+
id | id | id | id | id | id | id | id | id | id | id | id | id | id | id | id | id | id | id | id
4224+
----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----
4225+
(0 rows)
4226+
4227+
select (trunc(extract(epoch from now())) - :unix_time1) < 100 is_ok;
4228+
is_ok
4229+
-------
4230+
t
4231+
(1 row)
4232+
4233+
reset optimizer;
41924234
-- Clean up. None of the objects we create are very interesting to keep around.
41934235
reset search_path;
41944236
set client_min_messages='warning';

src/test/regress/expected/bfv_joins_optimizer.out

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4206,6 +4206,48 @@ INSERT INTO ext_stats_tbl VALUES('tC', true);
42064206
ANALYZE ext_stats_tbl;
42074207
explain SELECT 1 FROM ext_stats_tbl t11 FULL JOIN ext_stats_tbl t12 ON t12.c2;
42084208
ERROR: FULL JOIN is only supported with merge-joinable or hash-joinable join conditions
4209+
-- Check that Postgres Planner can build a plan with 20 joins in reasonable time
4210+
do $$
4211+
begin
4212+
for i in 1..20 loop
4213+
execute 'create table tj' || i || '(id int)';
4214+
end loop;
4215+
end
4216+
$$;
4217+
set optimizer to off;
4218+
select trunc(extract(epoch from now())) unix_time1 \gset
4219+
select *
4220+
from tj1
4221+
join tj2 on tj1.id = tj2.id
4222+
join tj3 on tj2.id = tj3.id
4223+
join tj4 on tj3.id = tj4.id
4224+
join tj5 on tj4.id = tj5.id
4225+
join tj6 on tj5.id = tj6.id
4226+
join tj7 on tj6.id = tj7.id
4227+
join tj8 on tj7.id = tj8.id
4228+
join tj9 on tj8.id = tj9.id
4229+
join tj10 on tj9.id = tj10.id
4230+
join tj11 on tj10.id = tj11.id
4231+
join tj12 on tj11.id = tj12.id
4232+
join tj13 on tj12.id = tj13.id
4233+
join tj14 on tj13.id = tj14.id
4234+
join tj15 on tj14.id = tj15.id
4235+
join tj16 on tj15.id = tj16.id
4236+
join tj17 on tj16.id = tj17.id
4237+
join tj18 on tj17.id = tj18.id
4238+
join tj19 on tj18.id = tj19.id
4239+
join tj20 on tj19.id = tj20.id;
4240+
id | id | id | id | id | id | id | id | id | id | id | id | id | id | id | id | id | id | id | id
4241+
----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----
4242+
(0 rows)
4243+
4244+
select (trunc(extract(epoch from now())) - :unix_time1) < 100 is_ok;
4245+
is_ok
4246+
-------
4247+
t
4248+
(1 row)
4249+
4250+
reset optimizer;
42094251
-- Clean up. None of the objects we create are very interesting to keep around.
42104252
reset search_path;
42114253
set client_min_messages='warning';

src/test/regress/sql/bfv_joins.sql

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,45 @@ ANALYZE ext_stats_tbl;
604604

605605
explain SELECT 1 FROM ext_stats_tbl t11 FULL JOIN ext_stats_tbl t12 ON t12.c2;
606606

607+
-- Check that Postgres Planner can build a plan with 20 joins in reasonable time
608+
do $$
609+
begin
610+
for i in 1..20 loop
611+
execute 'create table tj' || i || '(id int)';
612+
end loop;
613+
end
614+
$$;
615+
616+
set optimizer to off;
617+
618+
select trunc(extract(epoch from now())) unix_time1 \gset
619+
620+
select *
621+
from tj1
622+
join tj2 on tj1.id = tj2.id
623+
join tj3 on tj2.id = tj3.id
624+
join tj4 on tj3.id = tj4.id
625+
join tj5 on tj4.id = tj5.id
626+
join tj6 on tj5.id = tj6.id
627+
join tj7 on tj6.id = tj7.id
628+
join tj8 on tj7.id = tj8.id
629+
join tj9 on tj8.id = tj9.id
630+
join tj10 on tj9.id = tj10.id
631+
join tj11 on tj10.id = tj11.id
632+
join tj12 on tj11.id = tj12.id
633+
join tj13 on tj12.id = tj13.id
634+
join tj14 on tj13.id = tj14.id
635+
join tj15 on tj14.id = tj15.id
636+
join tj16 on tj15.id = tj16.id
637+
join tj17 on tj16.id = tj17.id
638+
join tj18 on tj17.id = tj18.id
639+
join tj19 on tj18.id = tj19.id
640+
join tj20 on tj19.id = tj20.id;
641+
642+
select (trunc(extract(epoch from now())) - :unix_time1) < 100 is_ok;
643+
644+
reset optimizer;
645+
607646
-- Clean up. None of the objects we create are very interesting to keep around.
608647
reset search_path;
609648
set client_min_messages='warning';

0 commit comments

Comments
 (0)