Specifies that our CustomScan providers support projections (#6244)

Before, this was the default mode for CustomScan providers.
Now, the default is to assume that they can't project.
This causes performance penalties due to adding unnecessary
Result nodes.

Hence we use the newly added flag, CUSTOMPATH_SUPPORT_PROJECTION
to get it back to how it was.

In PG15 support branch we created explain functions to ignore
the new Result nodes, so we undo that in this commit.

Relevant PG commit:
955b3e0f9269639fb916cee3dea37aee50b82df0
marcocitus/fix-subplan-local-execution
Naisila Puka 2022-08-31 10:48:01 +03:00 committed by GitHub
parent 24e695ca27
commit 98dcbeb304
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1616 additions and 159 deletions

View File

@ -1303,6 +1303,12 @@ AddColumnarScanPath(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte,
cpath->methods = &ColumnarScanPathMethods; cpath->methods = &ColumnarScanPathMethods;
#if (PG_VERSION_NUM >= PG_VERSION_15)
/* necessary to avoid extra Result node in PG15 */
cpath->flags = CUSTOMPATH_SUPPORT_PROJECTION;
#endif
/* /*
* populate generic path information * populate generic path information
*/ */
@ -1545,6 +1551,12 @@ ColumnarScanPath_PlanCustomPath(PlannerInfo *root,
cscan->scan.plan.targetlist = list_copy(tlist); cscan->scan.plan.targetlist = list_copy(tlist);
cscan->scan.scanrelid = best_path->path.parent->relid; cscan->scan.scanrelid = best_path->path.parent->relid;
#if (PG_VERSION_NUM >= 150000)
/* necessary to avoid extra Result node in PG15 */
cscan->flags = CUSTOMPATH_SUPPORT_PROJECTION;
#endif
return (Plan *) cscan; return (Plan *) cscan;
} }

View File

@ -136,6 +136,12 @@ CreateCitusCustomScanPath(PlannerInfo *root, RelOptInfo *relOptInfo,
path->custom_path.path.pathtarget = relOptInfo->reltarget; path->custom_path.path.pathtarget = relOptInfo->reltarget;
path->custom_path.path.parent = relOptInfo; path->custom_path.path.parent = relOptInfo;
#if (PG_VERSION_NUM >= PG_VERSION_15)
/* necessary to avoid extra Result node in PG15 */
path->custom_path.flags = CUSTOMPATH_SUPPORT_PROJECTION;
#endif
/* /*
* The 100k rows we put on the cost of the path is kind of arbitrary and could be * The 100k rows we put on the cost of the path is kind of arbitrary and could be
* improved in accuracy to produce better plans. * improved in accuracy to produce better plans.

View File

@ -1369,7 +1369,14 @@ FinalizePlan(PlannedStmt *localPlan, DistributedPlan *distributedPlan)
Node *distributedPlanData = (Node *) distributedPlan; Node *distributedPlanData = (Node *) distributedPlan;
customScan->custom_private = list_make1(distributedPlanData); customScan->custom_private = list_make1(distributedPlanData);
#if (PG_VERSION_NUM >= PG_VERSION_15)
/* necessary to avoid extra Result node in PG15 */
customScan->flags = CUSTOMPATH_SUPPORT_BACKWARD_SCAN | CUSTOMPATH_SUPPORT_PROJECTION;
#else
customScan->flags = CUSTOMPATH_SUPPORT_BACKWARD_SCAN; customScan->flags = CUSTOMPATH_SUPPORT_BACKWARD_SCAN;
#endif
/* /*
* Fast path queries cannot have any subplans by definition, so skip * Fast path queries cannot have any subplans by definition, so skip

View File

@ -264,21 +264,17 @@ EXPLAIN (analyze on, costs off, timing off, summary off)
Columnar Projected Columns: a Columnar Projected Columns: a
(9 rows) (9 rows)
SELECT plan_without_arrows($Q$
EXPLAIN (costs off, timing off, summary off) EXPLAIN (costs off, timing off, summary off)
SELECT y, * FROM another_columnar_table; SELECT y, * FROM another_columnar_table;
$Q$); QUERY PLAN
plan_without_arrows
--------------------------------------------------------------------- ---------------------------------------------------------------------
Custom Scan (ColumnarScan) on another_columnar_table Custom Scan (ColumnarScan) on another_columnar_table
Columnar Projected Columns: x, y Columnar Projected Columns: x, y
(2 rows) (2 rows)
SELECT plan_without_arrows($Q$
EXPLAIN (costs off, timing off, summary off) EXPLAIN (costs off, timing off, summary off)
SELECT *, x FROM another_columnar_table; SELECT *, x FROM another_columnar_table;
$Q$); QUERY PLAN
plan_without_arrows
--------------------------------------------------------------------- ---------------------------------------------------------------------
Custom Scan (ColumnarScan) on another_columnar_table Custom Scan (ColumnarScan) on another_columnar_table
Columnar Projected Columns: x, y Columnar Projected Columns: x, y

View File

@ -958,15 +958,13 @@ SELECT * FROM weird_col_explain;
(7 rows) (7 rows)
\set VERBOSITY terse \set VERBOSITY terse
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS OFF, SUMMARY OFF) EXPLAIN (COSTS OFF, SUMMARY OFF)
SELECT *, "bbbbbbbbbbbbbbbbbbbbbbbbb\!bbbb'bbbbbbbbbbbbbbbbbbbbb''bbbbbbbb" SELECT *, "bbbbbbbbbbbbbbbbbbbbbbbbb\!bbbb'bbbbbbbbbbbbbbbbbbbbb''bbbbbbbb"
FROM weird_col_explain FROM weird_col_explain
WHERE "bbbbbbbbbbbbbbbbbbbbbbbbb\!bbbb'bbbbbbbbbbbbbbbbbbbbb''bbbbbbbb" * 2 > WHERE "bbbbbbbbbbbbbbbbbbbbbbbbb\!bbbb'bbbbbbbbbbbbbbbbbbbbb''bbbbbbbb" * 2 >
"aaaaaaaaaaaa$aaaaaa$$aaaaaaaaaaaaaaaaaaaaaaaaaaaaa'aaaaaaaa'$a'!"; "aaaaaaaaaaaa$aaaaaa$$aaaaaaaaaaaaaaaaaaaaaaaaaaaaa'aaaaaaaa'$a'!";
$Q$);
NOTICE: identifier "aaaaaaaaaaaa$aaaaaa$$aaaaaaaaaaaaaaaaaaaaaaaaaaaaa'aaaaaaaa'$a'!" will be truncated to "aaaaaaaaaaaa$aaaaaa$$aaaaaaaaaaaaaaaaaaaaaaaaaaaaa'aaaaaaaa'$a'" NOTICE: identifier "aaaaaaaaaaaa$aaaaaa$$aaaaaaaaaaaaaaaaaaaaaaaaaaaaa'aaaaaaaa'$a'!" will be truncated to "aaaaaaaaaaaa$aaaaaa$$aaaaaaaaaaaaaaaaaaaaaaaaaaaaa'aaaaaaaa'$a'"
plan_without_result_lines QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
Custom Scan (Citus Adaptive) Custom Scan (Citus Adaptive)
Task Count: 4 Task Count: 4

View File

@ -1261,10 +1261,8 @@ NOTICE: copying the data has completed
(1 row) (1 row)
SELECT public.plan_without_result_lines($Q$
explain (costs off) insert into table_with_sequences select y, x from table_with_sequences; explain (costs off) insert into table_with_sequences select y, x from table_with_sequences;
$Q$); QUERY PLAN
plan_without_result_lines
--------------------------------------------------------------------- ---------------------------------------------------------------------
Custom Scan (Citus INSERT ... SELECT) Custom Scan (Citus INSERT ... SELECT)
INSERT/SELECT method: pull to coordinator INSERT/SELECT method: pull to coordinator
@ -1289,10 +1287,8 @@ NOTICE: copying the data has completed
(1 row) (1 row)
SELECT public.plan_without_result_lines($Q$
explain (costs off) insert into table_with_user_sequences select y, x from table_with_user_sequences; explain (costs off) insert into table_with_user_sequences select y, x from table_with_user_sequences;
$Q$); QUERY PLAN
plan_without_result_lines
--------------------------------------------------------------------- ---------------------------------------------------------------------
Custom Scan (Citus INSERT ... SELECT) Custom Scan (Citus INSERT ... SELECT)
INSERT/SELECT method: pull to coordinator INSERT/SELECT method: pull to coordinator

View File

@ -1261,10 +1261,8 @@ NOTICE: copying the data has completed
(1 row) (1 row)
SELECT public.plan_without_result_lines($Q$
explain (costs off) insert into table_with_sequences select y, x from table_with_sequences; explain (costs off) insert into table_with_sequences select y, x from table_with_sequences;
$Q$); QUERY PLAN
plan_without_result_lines
--------------------------------------------------------------------- ---------------------------------------------------------------------
Custom Scan (Citus INSERT ... SELECT) Custom Scan (Citus INSERT ... SELECT)
INSERT/SELECT method: pull to coordinator INSERT/SELECT method: pull to coordinator
@ -1289,10 +1287,8 @@ NOTICE: copying the data has completed
(1 row) (1 row)
SELECT public.plan_without_result_lines($Q$
explain (costs off) insert into table_with_user_sequences select y, x from table_with_user_sequences; explain (costs off) insert into table_with_user_sequences select y, x from table_with_user_sequences;
$Q$); QUERY PLAN
plan_without_result_lines
--------------------------------------------------------------------- ---------------------------------------------------------------------
Custom Scan (Citus INSERT ... SELECT) Custom Scan (Citus INSERT ... SELECT)
INSERT/SELECT method: pull to coordinator INSERT/SELECT method: pull to coordinator

View File

@ -3,6 +3,13 @@
-- --
-- Tests select distinct, and select distinct on features. -- Tests select distinct, and select distinct on features.
-- --
SHOW server_version \gset
SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15;
server_version_ge_15
---------------------------------------------------------------------
t
(1 row)
ANALYZE lineitem_hash_part; ANALYZE lineitem_hash_part;
-- function calls are supported -- function calls are supported
SELECT DISTINCT l_orderkey, now() FROM lineitem_hash_part LIMIT 0; SELECT DISTINCT l_orderkey, now() FROM lineitem_hash_part LIMIT 0;
@ -306,14 +313,12 @@ EXPLAIN (COSTS FALSE)
-- check the plan if the hash aggreate is disabled. We expect to see sort+unique -- check the plan if the hash aggreate is disabled. We expect to see sort+unique
-- instead of aggregate plan node to handle distinct. -- instead of aggregate plan node to handle distinct.
SET enable_hashagg TO off; SET enable_hashagg TO off;
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT DISTINCT count(*) SELECT DISTINCT count(*)
FROM lineitem_hash_part FROM lineitem_hash_part
GROUP BY l_suppkey, l_linenumber GROUP BY l_suppkey, l_linenumber
ORDER BY 1; ORDER BY 1;
$Q$); QUERY PLAN
plan_without_result_lines
--------------------------------------------------------------------- ---------------------------------------------------------------------
Unique Unique
-> Sort -> Sort
@ -382,15 +387,13 @@ EXPLAIN (COSTS FALSE)
-- check the plan if the hash aggreate is disabled. Similar to the explain of -- check the plan if the hash aggreate is disabled. Similar to the explain of
-- the query above. -- the query above.
SET enable_hashagg TO off; SET enable_hashagg TO off;
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT DISTINCT l_suppkey, count(*) SELECT DISTINCT l_suppkey, count(*)
FROM lineitem_hash_part FROM lineitem_hash_part
GROUP BY l_suppkey, l_linenumber GROUP BY l_suppkey, l_linenumber
ORDER BY 1 ORDER BY 1
LIMIT 10; LIMIT 10;
$Q$); QUERY PLAN
plan_without_result_lines
--------------------------------------------------------------------- ---------------------------------------------------------------------
Limit Limit
-> Unique -> Unique
@ -443,9 +446,10 @@ EXPLAIN (COSTS FALSE)
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
Limit Limit
-> Unique
-> Sort -> Sort
Sort Key: remote_scan.l_suppkey, ((pg_catalog.sum(remote_scan.avg) / pg_catalog.sum(remote_scan.avg_1))) Sort Key: remote_scan.l_suppkey, ((pg_catalog.sum(remote_scan.avg) / pg_catalog.sum(remote_scan.avg_1)))
-> HashAggregate
Group Key: remote_scan.l_suppkey, (pg_catalog.sum(remote_scan.avg) / pg_catalog.sum(remote_scan.avg_1))
-> HashAggregate -> HashAggregate
Group Key: remote_scan.l_suppkey, remote_scan.worker_column_4 Group Key: remote_scan.l_suppkey, remote_scan.worker_column_4
-> Custom Scan (Citus Adaptive) -> Custom Scan (Citus Adaptive)
@ -456,20 +460,18 @@ EXPLAIN (COSTS FALSE)
-> HashAggregate -> HashAggregate
Group Key: l_suppkey, l_linenumber Group Key: l_suppkey, l_linenumber
-> Seq Scan on lineitem_hash_part_360041 lineitem_hash_part -> Seq Scan on lineitem_hash_part_360041 lineitem_hash_part
(14 rows) (15 rows)
-- check the plan if the hash aggreate is disabled. This explain errors out due -- check the plan if the hash aggreate is disabled. This explain errors out due
-- to a bug right now, expectation must be corrected after fixing it. -- to a bug right now, expectation must be corrected after fixing it.
SET enable_hashagg TO off; SET enable_hashagg TO off;
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT DISTINCT l_suppkey, avg(l_partkey) SELECT DISTINCT l_suppkey, avg(l_partkey)
FROM lineitem_hash_part FROM lineitem_hash_part
GROUP BY l_suppkey, l_linenumber GROUP BY l_suppkey, l_linenumber
ORDER BY 1,2 ORDER BY 1,2
LIMIT 10; LIMIT 10;
$Q$); QUERY PLAN
plan_without_result_lines
--------------------------------------------------------------------- ---------------------------------------------------------------------
Limit Limit
-> Unique -> Unique
@ -539,15 +541,13 @@ EXPLAIN (COSTS FALSE)
-- check the plan if the hash aggreate is disabled. We expect to see sort+unique to -- check the plan if the hash aggreate is disabled. We expect to see sort+unique to
-- handle distinct on. -- handle distinct on.
SET enable_hashagg TO off; SET enable_hashagg TO off;
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT DISTINCT ON (l_suppkey) avg(l_partkey) SELECT DISTINCT ON (l_suppkey) avg(l_partkey)
FROM lineitem_hash_part FROM lineitem_hash_part
GROUP BY l_suppkey, l_linenumber GROUP BY l_suppkey, l_linenumber
ORDER BY l_suppkey,1 ORDER BY l_suppkey,1
LIMIT 10; LIMIT 10;
$Q$); QUERY PLAN
plan_without_result_lines
--------------------------------------------------------------------- ---------------------------------------------------------------------
Limit Limit
-> Unique -> Unique
@ -598,9 +598,10 @@ EXPLAIN (COSTS FALSE)
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
Limit Limit
-> Unique
-> Sort -> Sort
Sort Key: ((sum(remote_scan.avg) / (pg_catalog.sum(remote_scan.avg_1))::double precision)) Sort Key: ((sum(remote_scan.avg) / (pg_catalog.sum(remote_scan.avg_1))::double precision))
-> HashAggregate
Group Key: (sum(remote_scan.avg) / (pg_catalog.sum(remote_scan.avg_1))::double precision)
-> HashAggregate -> HashAggregate
Group Key: remote_scan.worker_column_3, remote_scan.worker_column_4 Group Key: remote_scan.worker_column_3, remote_scan.worker_column_4
-> Custom Scan (Citus Adaptive) -> Custom Scan (Citus Adaptive)
@ -611,20 +612,18 @@ EXPLAIN (COSTS FALSE)
-> HashAggregate -> HashAggregate
Group Key: l_suppkey, l_linenumber Group Key: l_suppkey, l_linenumber
-> Seq Scan on lineitem_hash_part_360041 lineitem_hash_part -> Seq Scan on lineitem_hash_part_360041 lineitem_hash_part
(14 rows) (15 rows)
-- check the plan if the hash aggreate is disabled. This explain errors out due -- check the plan if the hash aggreate is disabled. This explain errors out due
-- to a bug right now, expectation must be corrected after fixing it. -- to a bug right now, expectation must be corrected after fixing it.
SET enable_hashagg TO off; SET enable_hashagg TO off;
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT DISTINCT avg(ceil(l_partkey / 2)) SELECT DISTINCT avg(ceil(l_partkey / 2))
FROM lineitem_hash_part FROM lineitem_hash_part
GROUP BY l_suppkey, l_linenumber GROUP BY l_suppkey, l_linenumber
ORDER BY 1 ORDER BY 1
LIMIT 10; LIMIT 10;
$Q$); QUERY PLAN
plan_without_result_lines
--------------------------------------------------------------------- ---------------------------------------------------------------------
Limit Limit
-> Unique -> Unique
@ -675,9 +674,10 @@ EXPLAIN (COSTS FALSE)
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
Limit Limit
-> Unique
-> Sort -> Sort
Sort Key: (((pg_catalog.sum(remote_scan.dis))::bigint + COALESCE((pg_catalog.sum(remote_scan.dis_1))::bigint, '0'::bigint))) Sort Key: (((pg_catalog.sum(remote_scan.dis))::bigint + COALESCE((pg_catalog.sum(remote_scan.dis_1))::bigint, '0'::bigint)))
-> HashAggregate
Group Key: ((pg_catalog.sum(remote_scan.dis))::bigint + COALESCE((pg_catalog.sum(remote_scan.dis_1))::bigint, '0'::bigint))
-> HashAggregate -> HashAggregate
Group Key: remote_scan.worker_column_3, remote_scan.worker_column_4 Group Key: remote_scan.worker_column_3, remote_scan.worker_column_4
-> Custom Scan (Citus Adaptive) -> Custom Scan (Citus Adaptive)
@ -688,20 +688,18 @@ EXPLAIN (COSTS FALSE)
-> HashAggregate -> HashAggregate
Group Key: l_suppkey, l_linenumber Group Key: l_suppkey, l_linenumber
-> Seq Scan on lineitem_hash_part_360041 lineitem_hash_part -> Seq Scan on lineitem_hash_part_360041 lineitem_hash_part
(14 rows) (15 rows)
-- check the plan if the hash aggreate is disabled. This explain errors out due -- check the plan if the hash aggreate is disabled. This explain errors out due
-- to a bug right now, expectation must be corrected after fixing it. -- to a bug right now, expectation must be corrected after fixing it.
SET enable_hashagg TO off; SET enable_hashagg TO off;
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT DISTINCT sum(l_suppkey) + count(l_partkey) AS dis SELECT DISTINCT sum(l_suppkey) + count(l_partkey) AS dis
FROM lineitem_hash_part FROM lineitem_hash_part
GROUP BY l_suppkey, l_linenumber GROUP BY l_suppkey, l_linenumber
ORDER BY 1 ORDER BY 1
LIMIT 10; LIMIT 10;
$Q$); QUERY PLAN
plan_without_result_lines
--------------------------------------------------------------------- ---------------------------------------------------------------------
Limit Limit
-> Unique -> Unique
@ -910,14 +908,12 @@ EXPLAIN (COSTS FALSE)
-- check the plan if the hash aggreate is disabled -- check the plan if the hash aggreate is disabled
SET enable_hashagg TO off; SET enable_hashagg TO off;
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT DISTINCT ceil(count(case when l_partkey > 100000 THEN 1 ELSE 0 END) / 2) AS count SELECT DISTINCT ceil(count(case when l_partkey > 100000 THEN 1 ELSE 0 END) / 2) AS count
FROM lineitem_hash_part FROM lineitem_hash_part
GROUP BY l_suppkey GROUP BY l_suppkey
ORDER BY 1; ORDER BY 1;
$Q$); QUERY PLAN
plan_without_result_lines
--------------------------------------------------------------------- ---------------------------------------------------------------------
Unique Unique
-> Sort -> Sort

File diff suppressed because it is too large Load Diff

View File

@ -17,15 +17,10 @@ BEGIN
END; END;
$$LANGUAGE plpgsql; $$LANGUAGE plpgsql;
-- Create a function to ignore worker plans in explain output -- Create a function to ignore worker plans in explain output
-- Also remove extra "-> Result" lines for PG15 support
CREATE OR REPLACE FUNCTION coordinator_plan(explain_command text, out query_plan text) CREATE OR REPLACE FUNCTION coordinator_plan(explain_command text, out query_plan text)
RETURNS SETOF TEXT AS $$ RETURNS SETOF TEXT AS $$
BEGIN BEGIN
FOR query_plan IN execute explain_command LOOP FOR query_plan IN execute explain_command LOOP
IF (query_plan LIKE '%-> Result%' OR query_plan = 'Result')
THEN
CONTINUE;
END IF;
RETURN next; RETURN next;
IF query_plan LIKE '%Task Count:%' IF query_plan LIKE '%Task Count:%'
THEN THEN
@ -36,16 +31,12 @@ BEGIN
END; $$ language plpgsql; END; $$ language plpgsql;
-- Create a function to ignore worker plans in explain output -- Create a function to ignore worker plans in explain output
-- It also shows task count for plan and subplans -- It also shows task count for plan and subplans
-- Also remove extra "-> Result" lines for PG15 support
CREATE OR REPLACE FUNCTION coordinator_plan_with_subplans(explain_command text, out query_plan text) CREATE OR REPLACE FUNCTION coordinator_plan_with_subplans(explain_command text, out query_plan text)
RETURNS SETOF TEXT AS $$ RETURNS SETOF TEXT AS $$
DECLARE DECLARE
task_count_line_reached boolean := false; task_count_line_reached boolean := false;
BEGIN BEGIN
FOR query_plan IN execute explain_command LOOP FOR query_plan IN execute explain_command LOOP
IF (query_plan LIKE '%-> Result%' OR query_plan = 'Result') THEN
CONTINUE;
END IF;
IF NOT task_count_line_reached THEN IF NOT task_count_line_reached THEN
RETURN next; RETURN next;
END IF; END IF;
@ -59,19 +50,6 @@ BEGIN
END LOOP; END LOOP;
RETURN; RETURN;
END; $$ language plpgsql; END; $$ language plpgsql;
-- Create a function to ignore "-> Result" lines for PG15 support
-- In PG15 there are some extra "-> Result" lines
CREATE OR REPLACE FUNCTION plan_without_result_lines(explain_command text, out query_plan text)
RETURNS SETOF TEXT AS $$
BEGIN
FOR query_plan IN execute explain_command LOOP
IF (query_plan LIKE '%-> Result%' OR query_plan = 'Result') THEN
CONTINUE;
END IF;
RETURN next;
END LOOP;
RETURN;
END; $$ language plpgsql;
-- Create a function to normalize Memory Usage, Buckets, Batches -- Create a function to normalize Memory Usage, Buckets, Batches
CREATE OR REPLACE FUNCTION plan_normalize_memory(explain_command text, out query_plan text) CREATE OR REPLACE FUNCTION plan_normalize_memory(explain_command text, out query_plan text)
RETURNS SETOF TEXT AS $$ RETURNS SETOF TEXT AS $$
@ -81,18 +59,6 @@ BEGIN
RETURN NEXT; RETURN NEXT;
END LOOP; END LOOP;
END; $$ language plpgsql; END; $$ language plpgsql;
-- Create a function to remove arrows from the explain plan
CREATE OR REPLACE FUNCTION plan_without_arrows(explain_command text, out query_plan text)
RETURNS SETOF TEXT AS $$
BEGIN
FOR query_plan IN execute explain_command LOOP
IF (query_plan LIKE '%-> Result%' OR query_plan = 'Result') THEN
CONTINUE;
END IF;
query_plan := regexp_replace(query_plan, '( )*-> (.*)', '\2', 'g');
RETURN NEXT;
END LOOP;
END; $$ language plpgsql;
-- helper function that returns true if output of given explain has "is not null" (case in-sensitive) -- helper function that returns true if output of given explain has "is not null" (case in-sensitive)
CREATE OR REPLACE FUNCTION explain_has_is_not_null(explain_command text) CREATE OR REPLACE FUNCTION explain_has_is_not_null(explain_command text)
RETURNS BOOLEAN AS $$ RETURNS BOOLEAN AS $$

View File

@ -1491,12 +1491,10 @@ LIMIT 5;
(17 rows) (17 rows)
-- Grouping can be pushed down with aggregates even when window function can't -- Grouping can be pushed down with aggregates even when window function can't
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT user_id, count(value_1), stddev(value_1), count(user_id) OVER (PARTITION BY random()) SELECT user_id, count(value_1), stddev(value_1), count(user_id) OVER (PARTITION BY random())
FROM users_table GROUP BY user_id HAVING avg(value_1) > 2 LIMIT 1; FROM users_table GROUP BY user_id HAVING avg(value_1) > 2 LIMIT 1;
$Q$); QUERY PLAN
plan_without_result_lines
--------------------------------------------------------------------- ---------------------------------------------------------------------
Limit Limit
-> WindowAgg -> WindowAgg

View File

@ -1495,12 +1495,10 @@ LIMIT 5;
(18 rows) (18 rows)
-- Grouping can be pushed down with aggregates even when window function can't -- Grouping can be pushed down with aggregates even when window function can't
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT user_id, count(value_1), stddev(value_1), count(user_id) OVER (PARTITION BY random()) SELECT user_id, count(value_1), stddev(value_1), count(user_id) OVER (PARTITION BY random())
FROM users_table GROUP BY user_id HAVING avg(value_1) > 2 LIMIT 1; FROM users_table GROUP BY user_id HAVING avg(value_1) > 2 LIMIT 1;
$Q$); QUERY PLAN
plan_without_result_lines
--------------------------------------------------------------------- ---------------------------------------------------------------------
Limit Limit
-> WindowAgg -> WindowAgg

View File

@ -130,15 +130,11 @@ INSERT INTO another_columnar_table SELECT generate_series(0,5);
EXPLAIN (analyze on, costs off, timing off, summary off) EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT a, y FROM multi_column_chunk_filtering, another_columnar_table WHERE x > 1; SELECT a, y FROM multi_column_chunk_filtering, another_columnar_table WHERE x > 1;
SELECT plan_without_arrows($Q$
EXPLAIN (costs off, timing off, summary off) EXPLAIN (costs off, timing off, summary off)
SELECT y, * FROM another_columnar_table; SELECT y, * FROM another_columnar_table;
$Q$);
SELECT plan_without_arrows($Q$
EXPLAIN (costs off, timing off, summary off) EXPLAIN (costs off, timing off, summary off)
SELECT *, x FROM another_columnar_table; SELECT *, x FROM another_columnar_table;
$Q$);
EXPLAIN (costs off, timing off, summary off) EXPLAIN (costs off, timing off, summary off)
SELECT y, another_columnar_table FROM another_columnar_table; SELECT y, another_columnar_table FROM another_columnar_table;

View File

@ -429,13 +429,11 @@ EXPLAIN (COSTS OFF, SUMMARY OFF)
SELECT * FROM weird_col_explain; SELECT * FROM weird_col_explain;
\set VERBOSITY terse \set VERBOSITY terse
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS OFF, SUMMARY OFF) EXPLAIN (COSTS OFF, SUMMARY OFF)
SELECT *, "bbbbbbbbbbbbbbbbbbbbbbbbb\!bbbb'bbbbbbbbbbbbbbbbbbbbb''bbbbbbbb" SELECT *, "bbbbbbbbbbbbbbbbbbbbbbbbb\!bbbb'bbbbbbbbbbbbbbbbbbbbb''bbbbbbbb"
FROM weird_col_explain FROM weird_col_explain
WHERE "bbbbbbbbbbbbbbbbbbbbbbbbb\!bbbb'bbbbbbbbbbbbbbbbbbbbb''bbbbbbbb" * 2 > WHERE "bbbbbbbbbbbbbbbbbbbbbbbbb\!bbbb'bbbbbbbbbbbbbbbbbbbbb''bbbbbbbb" * 2 >
"aaaaaaaaaaaa$aaaaaa$$aaaaaaaaaaaaaaaaaaaaaaaaaaaaa'aaaaaaaa'$a'!"; "aaaaaaaaaaaa$aaaaaa$$aaaaaaaaaaaaaaaaaaaaaaaaaaaaa'aaaaaaaa'$a'!";
$Q$);
\set VERBOSITY default \set VERBOSITY default
-- should not project any columns -- should not project any columns

View File

@ -635,9 +635,7 @@ DO UPDATE SET
create table table_with_sequences (x int, y int, z bigserial); create table table_with_sequences (x int, y int, z bigserial);
insert into table_with_sequences values (1,1); insert into table_with_sequences values (1,1);
select create_distributed_table('table_with_sequences','x'); select create_distributed_table('table_with_sequences','x');
SELECT public.plan_without_result_lines($Q$
explain (costs off) insert into table_with_sequences select y, x from table_with_sequences; explain (costs off) insert into table_with_sequences select y, x from table_with_sequences;
$Q$);
-- verify that we don't report repartitioned insert/select for tables -- verify that we don't report repartitioned insert/select for tables
-- with user-defined sequences. -- with user-defined sequences.
@ -645,9 +643,7 @@ CREATE SEQUENCE user_defined_sequence;
create table table_with_user_sequences (x int, y int, z bigint default nextval('user_defined_sequence')); create table table_with_user_sequences (x int, y int, z bigint default nextval('user_defined_sequence'));
insert into table_with_user_sequences values (1,1); insert into table_with_user_sequences values (1,1);
select create_distributed_table('table_with_user_sequences','x'); select create_distributed_table('table_with_user_sequences','x');
SELECT public.plan_without_result_lines($Q$
explain (costs off) insert into table_with_user_sequences select y, x from table_with_user_sequences; explain (costs off) insert into table_with_user_sequences select y, x from table_with_user_sequences;
$Q$);
-- clean-up -- clean-up
SET client_min_messages TO WARNING; SET client_min_messages TO WARNING;

View File

@ -3,6 +3,8 @@
-- --
-- Tests select distinct, and select distinct on features. -- Tests select distinct, and select distinct on features.
-- --
SHOW server_version \gset
SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15;
ANALYZE lineitem_hash_part; ANALYZE lineitem_hash_part;
@ -113,13 +115,11 @@ EXPLAIN (COSTS FALSE)
-- check the plan if the hash aggreate is disabled. We expect to see sort+unique -- check the plan if the hash aggreate is disabled. We expect to see sort+unique
-- instead of aggregate plan node to handle distinct. -- instead of aggregate plan node to handle distinct.
SET enable_hashagg TO off; SET enable_hashagg TO off;
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT DISTINCT count(*) SELECT DISTINCT count(*)
FROM lineitem_hash_part FROM lineitem_hash_part
GROUP BY l_suppkey, l_linenumber GROUP BY l_suppkey, l_linenumber
ORDER BY 1; ORDER BY 1;
$Q$);
SET enable_hashagg TO on; SET enable_hashagg TO on;
@ -142,14 +142,12 @@ EXPLAIN (COSTS FALSE)
-- check the plan if the hash aggreate is disabled. Similar to the explain of -- check the plan if the hash aggreate is disabled. Similar to the explain of
-- the query above. -- the query above.
SET enable_hashagg TO off; SET enable_hashagg TO off;
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT DISTINCT l_suppkey, count(*) SELECT DISTINCT l_suppkey, count(*)
FROM lineitem_hash_part FROM lineitem_hash_part
GROUP BY l_suppkey, l_linenumber GROUP BY l_suppkey, l_linenumber
ORDER BY 1 ORDER BY 1
LIMIT 10; LIMIT 10;
$Q$);
SET enable_hashagg TO on; SET enable_hashagg TO on;
@ -173,14 +171,12 @@ EXPLAIN (COSTS FALSE)
-- check the plan if the hash aggreate is disabled. This explain errors out due -- check the plan if the hash aggreate is disabled. This explain errors out due
-- to a bug right now, expectation must be corrected after fixing it. -- to a bug right now, expectation must be corrected after fixing it.
SET enable_hashagg TO off; SET enable_hashagg TO off;
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT DISTINCT l_suppkey, avg(l_partkey) SELECT DISTINCT l_suppkey, avg(l_partkey)
FROM lineitem_hash_part FROM lineitem_hash_part
GROUP BY l_suppkey, l_linenumber GROUP BY l_suppkey, l_linenumber
ORDER BY 1,2 ORDER BY 1,2
LIMIT 10; LIMIT 10;
$Q$);
SET enable_hashagg TO on; SET enable_hashagg TO on;
@ -203,14 +199,12 @@ EXPLAIN (COSTS FALSE)
-- check the plan if the hash aggreate is disabled. We expect to see sort+unique to -- check the plan if the hash aggreate is disabled. We expect to see sort+unique to
-- handle distinct on. -- handle distinct on.
SET enable_hashagg TO off; SET enable_hashagg TO off;
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT DISTINCT ON (l_suppkey) avg(l_partkey) SELECT DISTINCT ON (l_suppkey) avg(l_partkey)
FROM lineitem_hash_part FROM lineitem_hash_part
GROUP BY l_suppkey, l_linenumber GROUP BY l_suppkey, l_linenumber
ORDER BY l_suppkey,1 ORDER BY l_suppkey,1
LIMIT 10; LIMIT 10;
$Q$);
SET enable_hashagg TO on; SET enable_hashagg TO on;
@ -232,14 +226,12 @@ EXPLAIN (COSTS FALSE)
-- check the plan if the hash aggreate is disabled. This explain errors out due -- check the plan if the hash aggreate is disabled. This explain errors out due
-- to a bug right now, expectation must be corrected after fixing it. -- to a bug right now, expectation must be corrected after fixing it.
SET enable_hashagg TO off; SET enable_hashagg TO off;
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT DISTINCT avg(ceil(l_partkey / 2)) SELECT DISTINCT avg(ceil(l_partkey / 2))
FROM lineitem_hash_part FROM lineitem_hash_part
GROUP BY l_suppkey, l_linenumber GROUP BY l_suppkey, l_linenumber
ORDER BY 1 ORDER BY 1
LIMIT 10; LIMIT 10;
$Q$);
SET enable_hashagg TO on; SET enable_hashagg TO on;
@ -261,14 +253,12 @@ EXPLAIN (COSTS FALSE)
-- check the plan if the hash aggreate is disabled. This explain errors out due -- check the plan if the hash aggreate is disabled. This explain errors out due
-- to a bug right now, expectation must be corrected after fixing it. -- to a bug right now, expectation must be corrected after fixing it.
SET enable_hashagg TO off; SET enable_hashagg TO off;
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT DISTINCT sum(l_suppkey) + count(l_partkey) AS dis SELECT DISTINCT sum(l_suppkey) + count(l_partkey) AS dis
FROM lineitem_hash_part FROM lineitem_hash_part
GROUP BY l_suppkey, l_linenumber GROUP BY l_suppkey, l_linenumber
ORDER BY 1 ORDER BY 1
LIMIT 10; LIMIT 10;
$Q$);
SET enable_hashagg TO on; SET enable_hashagg TO on;
@ -345,13 +335,11 @@ EXPLAIN (COSTS FALSE)
-- check the plan if the hash aggreate is disabled -- check the plan if the hash aggreate is disabled
SET enable_hashagg TO off; SET enable_hashagg TO off;
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT DISTINCT ceil(count(case when l_partkey > 100000 THEN 1 ELSE 0 END) / 2) AS count SELECT DISTINCT ceil(count(case when l_partkey > 100000 THEN 1 ELSE 0 END) / 2) AS count
FROM lineitem_hash_part FROM lineitem_hash_part
GROUP BY l_suppkey GROUP BY l_suppkey
ORDER BY 1; ORDER BY 1;
$Q$);
SET enable_hashagg TO on; SET enable_hashagg TO on;

View File

@ -20,15 +20,10 @@ END;
$$LANGUAGE plpgsql; $$LANGUAGE plpgsql;
-- Create a function to ignore worker plans in explain output -- Create a function to ignore worker plans in explain output
-- Also remove extra "-> Result" lines for PG15 support
CREATE OR REPLACE FUNCTION coordinator_plan(explain_command text, out query_plan text) CREATE OR REPLACE FUNCTION coordinator_plan(explain_command text, out query_plan text)
RETURNS SETOF TEXT AS $$ RETURNS SETOF TEXT AS $$
BEGIN BEGIN
FOR query_plan IN execute explain_command LOOP FOR query_plan IN execute explain_command LOOP
IF (query_plan LIKE '%-> Result%' OR query_plan = 'Result')
THEN
CONTINUE;
END IF;
RETURN next; RETURN next;
IF query_plan LIKE '%Task Count:%' IF query_plan LIKE '%Task Count:%'
THEN THEN
@ -40,16 +35,12 @@ END; $$ language plpgsql;
-- Create a function to ignore worker plans in explain output -- Create a function to ignore worker plans in explain output
-- It also shows task count for plan and subplans -- It also shows task count for plan and subplans
-- Also remove extra "-> Result" lines for PG15 support
CREATE OR REPLACE FUNCTION coordinator_plan_with_subplans(explain_command text, out query_plan text) CREATE OR REPLACE FUNCTION coordinator_plan_with_subplans(explain_command text, out query_plan text)
RETURNS SETOF TEXT AS $$ RETURNS SETOF TEXT AS $$
DECLARE DECLARE
task_count_line_reached boolean := false; task_count_line_reached boolean := false;
BEGIN BEGIN
FOR query_plan IN execute explain_command LOOP FOR query_plan IN execute explain_command LOOP
IF (query_plan LIKE '%-> Result%' OR query_plan = 'Result') THEN
CONTINUE;
END IF;
IF NOT task_count_line_reached THEN IF NOT task_count_line_reached THEN
RETURN next; RETURN next;
END IF; END IF;
@ -64,20 +55,6 @@ BEGIN
RETURN; RETURN;
END; $$ language plpgsql; END; $$ language plpgsql;
-- Create a function to ignore "-> Result" lines for PG15 support
-- In PG15 there are some extra "-> Result" lines
CREATE OR REPLACE FUNCTION plan_without_result_lines(explain_command text, out query_plan text)
RETURNS SETOF TEXT AS $$
BEGIN
FOR query_plan IN execute explain_command LOOP
IF (query_plan LIKE '%-> Result%' OR query_plan = 'Result') THEN
CONTINUE;
END IF;
RETURN next;
END LOOP;
RETURN;
END; $$ language plpgsql;
-- Create a function to normalize Memory Usage, Buckets, Batches -- Create a function to normalize Memory Usage, Buckets, Batches
CREATE OR REPLACE FUNCTION plan_normalize_memory(explain_command text, out query_plan text) CREATE OR REPLACE FUNCTION plan_normalize_memory(explain_command text, out query_plan text)
RETURNS SETOF TEXT AS $$ RETURNS SETOF TEXT AS $$
@ -88,19 +65,6 @@ BEGIN
END LOOP; END LOOP;
END; $$ language plpgsql; END; $$ language plpgsql;
-- Create a function to remove arrows from the explain plan
CREATE OR REPLACE FUNCTION plan_without_arrows(explain_command text, out query_plan text)
RETURNS SETOF TEXT AS $$
BEGIN
FOR query_plan IN execute explain_command LOOP
IF (query_plan LIKE '%-> Result%' OR query_plan = 'Result') THEN
CONTINUE;
END IF;
query_plan := regexp_replace(query_plan, '( )*-> (.*)', '\2', 'g');
RETURN NEXT;
END LOOP;
END; $$ language plpgsql;
-- helper function that returns true if output of given explain has "is not null" (case in-sensitive) -- helper function that returns true if output of given explain has "is not null" (case in-sensitive)
CREATE OR REPLACE FUNCTION explain_has_is_not_null(explain_command text) CREATE OR REPLACE FUNCTION explain_has_is_not_null(explain_command text)
RETURNS BOOLEAN AS $$ RETURNS BOOLEAN AS $$

View File

@ -576,11 +576,9 @@ ORDER BY user_id, avg(value_1) DESC
LIMIT 5; LIMIT 5;
-- Grouping can be pushed down with aggregates even when window function can't -- Grouping can be pushed down with aggregates even when window function can't
SELECT public.plan_without_result_lines($Q$
EXPLAIN (COSTS FALSE) EXPLAIN (COSTS FALSE)
SELECT user_id, count(value_1), stddev(value_1), count(user_id) OVER (PARTITION BY random()) SELECT user_id, count(value_1), stddev(value_1), count(user_id) OVER (PARTITION BY random())
FROM users_table GROUP BY user_id HAVING avg(value_1) > 2 LIMIT 1; FROM users_table GROUP BY user_id HAVING avg(value_1) > 2 LIMIT 1;
$Q$);
-- Window function with inlined CTE -- Window function with inlined CTE
WITH cte as ( WITH cte as (