From 554f458ffd215ba6a66bb85d29135e6b8c82f581 Mon Sep 17 00:00:00 2001 From: Zhang Wenchao Date: Fri, 3 Jul 2026 10:45:20 +0800 Subject: [PATCH] Fix ORCA direct dispatch for multi-value quals For a predicate restricting the distribution key to several constants, e.g. WHERE dist_key IN (c1, c2), the Postgres planner direct-dispatches the slice to the union of the segments the constants hash to. GPORCA gave up instead: the optimizer side already emits one datum array per value into CDXLDirectDispatchInfo, but TranslateDXLDirectDispatchInfo required every value to hash to the same segment and returned NIL otherwise, so the query was dispatched to all segments. Collect the distinct content ids of all datum combinations instead, mirroring the planner's MergeDirectDispatchCalculationInfo behavior. A value set that spans every segment still returns NIL, since direct dispatch buys nothing there. PlanSlice->directDispatch.contentIds is already a list and the dispatcher handles multiple content ids, so no dispatcher change is needed. Add a gpdb::LAppendUniqueInt wrapper for list_append_unique_int. On a 3-segment cluster, "select * from t1_varchar where col1_varchar in ('a','b')" now dispatches to 2 segments (PARTIAL contents) instead of all 3, matching the planner. Single-value and same-segment cases are unchanged, as is the raw-values gp_segment_id path. Update the affected expected outputs: the direct_dispatch disjunction scenarios, the bfv_dd dispatch INFO lines, and the plans in create_index, inherit, partition, partition_append, partition_prune, partition_prune_append and qp_misc_jiras whose Gather Motion drops from 3:1 to 2:1, in src/test/regress as well as in the copies of these tests carried by the pax_storage and vectorization suites. --- .../regress/expected/bfv_dd_optimizer.out | 26 +++++++++--------- .../expected/create_index_optimizer.out | 2 +- .../expected/direct_dispatch_optimizer.out | 16 +++++------ .../regress/expected/inherit_optimizer.out | 16 +++++------ .../expected/partition_prune_optimizer.out | 8 +++--- .../expected/qp_misc_jiras_optimizer.out | 2 +- src/backend/gpopt/gpdbwrappers.cpp | 11 ++++++++ .../translate/CTranslatorDXLToPlStmt.cpp | 27 ++++++++++--------- src/include/gpopt/gpdbwrappers.h | 3 +++ .../regress/expected/bfv_dd_optimizer.out | 26 +++++++++--------- .../expected/create_index_optimizer.out | 2 +- .../expected/direct_dispatch_optimizer.out | 16 +++++------ .../regress/expected/inherit_optimizer.out | 16 +++++------ .../regress/expected/partition_append.out | 2 +- .../regress/expected/partition_optimizer.out | 2 +- .../expected/partition_prune_append.out | 8 +++--- .../expected/partition_prune_optimizer.out | 8 +++--- .../expected/qp_misc_jiras_optimizer.out | 2 +- 18 files changed, 105 insertions(+), 88 deletions(-) diff --git a/contrib/pax_storage/src/test/regress/expected/bfv_dd_optimizer.out b/contrib/pax_storage/src/test/regress/expected/bfv_dd_optimizer.out index deadff501d5..224d386ad0d 100644 --- a/contrib/pax_storage/src/test/regress/expected/bfv_dd_optimizer.out +++ b/contrib/pax_storage/src/test/regress/expected/bfv_dd_optimizer.out @@ -88,7 +88,7 @@ INFO: (slice 1) Dispatch command to SINGLE content -- single column distr key select * from dd_singlecol_1 where a in (10,11,12); -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 a | b ----+---- 10 | 10 @@ -97,7 +97,7 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 (3 rows) select * from dd_singlecol_1 where a=10 or a=11 or a=12; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 a | b ----+---- 10 | 10 @@ -106,7 +106,7 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 (3 rows) select * from dd_singlecol_1 where a is null or a=1; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 a | b ---+--- 1 | 1 @@ -115,7 +115,7 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 -- projections and disjunction select b from dd_singlecol_1 where a=1 or a=2; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 b --- 1 @@ -175,7 +175,7 @@ INFO: (slice 0) Dispatch command to SINGLE content INFO: Distributed transaction command 'Distributed Commit (one-phase)' to SINGLE content -- disjunction with partitioned tables select * from dd_part_singlecol where a in (10,11,12); -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 a | b | c ----+----+---- 10 | 20 | 30 @@ -184,7 +184,7 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 (3 rows) select * from dd_part_singlecol where a=10 or a=11 or a=12; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 a | b | c ----+----+---- 10 | 20 | 30 @@ -193,7 +193,7 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 (3 rows) select * from dd_part_singlecol where a is null or a=1; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 a | b | c ---+---+--- | | @@ -321,21 +321,21 @@ analyze dd_singlecol_idx2; INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 -- disjunction with index scans select * from dd_singlecol_idx where (a=1 or a=2) and b<2; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 a | b | c ---+---+--- 1 | 1 | 1 (1 row) select 'one' from dd_singlecol_idx where (a=1 or a=2) and b=1; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 ?column? ---------- one (1 row) select a, count(*) from dd_singlecol_idx where (a=1 or a=2) and b=1 group by a; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 a | count ---+------- 1 | 1 @@ -369,21 +369,21 @@ analyze dd_singlecol_bitmap_idx; INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 -- disjunction with bitmap index scans select * from dd_singlecol_bitmap_idx where (a=1 or a=2) and b<2; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 a | b | c ---+---+--- 1 | 1 | 1 (1 row) select * from dd_singlecol_bitmap_idx where (a=1 or a=2) and b=2 and c=2; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 a | b | c ---+---+--- 2 | 2 | 2 (1 row) select * from dd_singlecol_bitmap_idx where (a=1 or a=2) and (b=2 or c=2); -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 a | b | c ---+---+--- 2 | 2 | 2 diff --git a/contrib/pax_storage/src/test/regress/expected/create_index_optimizer.out b/contrib/pax_storage/src/test/regress/expected/create_index_optimizer.out index 56b70e3175c..40b610bf773 100644 --- a/contrib/pax_storage/src/test/regress/expected/create_index_optimizer.out +++ b/contrib/pax_storage/src/test/regress/expected/create_index_optimizer.out @@ -2013,7 +2013,7 @@ WHERE unique1 IN (1,42,7) ORDER BY unique1; QUERY PLAN ------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) Merge Key: unique1 -> Index Only Scan using tenk1_unique1 on tenk1 Index Cond: (unique1 = ANY ('{1,42,7}'::integer[])) diff --git a/contrib/pax_storage/src/test/regress/expected/direct_dispatch_optimizer.out b/contrib/pax_storage/src/test/regress/expected/direct_dispatch_optimizer.out index 8efc7ccfc0f..241b4101afe 100644 --- a/contrib/pax_storage/src/test/regress/expected/direct_dispatch_optimizer.out +++ b/contrib/pax_storage/src/test/regress/expected/direct_dispatch_optimizer.out @@ -1120,14 +1120,14 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 explain (costs off) select gp_segment_id, * from t1_varchar where col1_varchar in ('a','b'); QUERY PLAN ---------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Seq Scan on t1_varchar Filter: ((col1_varchar)::text = ANY ('{a,b}'::text[])) Optimizer: Pivotal Optimizer (GPORCA) (4 rows) select gp_segment_id, * from t1_varchar where col1_varchar in ('a','b'); -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 gp_segment_id | col1_varchar | col2_int ---------------+--------------+---------- 1 | b | 2 @@ -1137,14 +1137,14 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 explain (costs off) select gp_segment_id, * from t1_varchar where col1_varchar = 'a' or col1_varchar = 'b'; QUERY PLAN -------------------------------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Seq Scan on t1_varchar Filter: (((col1_varchar)::text = 'a'::text) OR ((col1_varchar)::text = 'b'::text)) Optimizer: Pivotal Optimizer (GPORCA) (4 rows) select gp_segment_id, * from t1_varchar where col1_varchar = 'a' or col1_varchar = 'b'; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 gp_segment_id | col1_varchar | col2_int ---------------+--------------+---------- 1 | b | 2 @@ -1204,14 +1204,14 @@ INFO: (slice 1) Dispatch command to SINGLE content explain (costs off) select gp_segment_id, * from t1_varchar where col1_varchar in ('a', 'b') and col2_int=2; QUERY PLAN ------------------------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Seq Scan on t1_varchar Filter: (((col1_varchar)::text = ANY ('{a,b}'::text[])) AND (col2_int = 2)) Optimizer: Pivotal Optimizer (GPORCA) (4 rows) select gp_segment_id, * from t1_varchar where col1_varchar in ('a', 'b') and col2_int=2; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 gp_segment_id | col1_varchar | col2_int ---------------+--------------+---------- 1 | b | 2 @@ -1220,14 +1220,14 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 explain (costs off) select gp_segment_id, * from t1_varchar where (col1_varchar = 'a' or col1_varchar = 'b') and col2_int=1; QUERY PLAN ----------------------------------------------------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Seq Scan on t1_varchar Filter: ((((col1_varchar)::text = 'a'::text) OR ((col1_varchar)::text = 'b'::text)) AND (col2_int = 1)) Optimizer: Pivotal Optimizer (GPORCA) (4 rows) select gp_segment_id, * from t1_varchar where (col1_varchar = 'a' or col1_varchar = 'b') and col2_int=1; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 gp_segment_id | col1_varchar | col2_int ---------------+--------------+---------- 2 | a | 1 diff --git a/contrib/pax_storage/src/test/regress/expected/inherit_optimizer.out b/contrib/pax_storage/src/test/regress/expected/inherit_optimizer.out index 1b7799140e5..378eb8b7cb6 100644 --- a/contrib/pax_storage/src/test/regress/expected/inherit_optimizer.out +++ b/contrib/pax_storage/src/test/regress/expected/inherit_optimizer.out @@ -2088,7 +2088,7 @@ explain (costs off) select * from list_parted where a is not null; explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef'); QUERY PLAN ---------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Dynamic Seq Scan on list_parted Number of partitions to scan: 2 (out of 3) Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[])) @@ -2098,7 +2098,7 @@ explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef'); explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd'); QUERY PLAN --------------------------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Dynamic Seq Scan on list_parted Number of partitions to scan: 1 (out of 3) Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[]))) @@ -2548,7 +2548,7 @@ explain (costs off) select * from mclparted order by a; explain (costs off) select * from mclparted where a in(3,4,5) order by a; QUERY PLAN --------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) Merge Key: a -> Sort Sort Key: a @@ -2565,7 +2565,7 @@ create table mclparted_def partition of mclparted default; explain (costs off) select * from mclparted where a in(1,2,4) order by a; QUERY PLAN --------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) Merge Key: a -> Sort Sort Key: a @@ -2578,7 +2578,7 @@ explain (costs off) select * from mclparted where a in(1,2,4) order by a; explain (costs off) select * from mclparted where a in(1,2,4) or a is null order by a; QUERY PLAN ------------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) Merge Key: a -> Sort Sort Key: a @@ -2595,7 +2595,7 @@ create table mclparted_0_null partition of mclparted for values in(0,null); explain (costs off) select * from mclparted where a in(1,2,4) or a is null order by a; QUERY PLAN ------------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) Merge Key: a -> Sort Sort Key: a @@ -2608,7 +2608,7 @@ explain (costs off) select * from mclparted where a in(1,2,4) or a is null order explain (costs off) select * from mclparted where a in(0,1,2,4) order by a; QUERY PLAN --------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) Merge Key: a -> Sort Sort Key: a @@ -2622,7 +2622,7 @@ explain (costs off) select * from mclparted where a in(0,1,2,4) order by a; explain (costs off) select * from mclparted where a in(1,2,4) order by a; QUERY PLAN --------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) Merge Key: a -> Sort Sort Key: a diff --git a/contrib/pax_storage/src/test/regress/expected/partition_prune_optimizer.out b/contrib/pax_storage/src/test/regress/expected/partition_prune_optimizer.out index c8c35129b79..a020be227ec 100644 --- a/contrib/pax_storage/src/test/regress/expected/partition_prune_optimizer.out +++ b/contrib/pax_storage/src/test/regress/expected/partition_prune_optimizer.out @@ -1600,7 +1600,7 @@ create table coercepart_cd partition of coercepart for values in ('cd'); explain (costs off) select * from coercepart where a in ('ab', to_char(125, '999')); QUERY PLAN ----------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Dynamic Seq Scan on coercepart Number of partitions to scan: 1 (out of 3) Filter: ((a)::text = ANY ('{ab," 125"}'::text[])) @@ -1650,7 +1650,7 @@ explain (costs off) select * from coercepart where a !~ all ('{ab,bc}'); explain (costs off) select * from coercepart where a = any ('{ab,bc}'); QUERY PLAN ------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Dynamic Seq Scan on coercepart Number of partitions to scan: 2 (out of 3) Filter: ((a)::text = ANY ('{ab,bc}'::text[])) @@ -1690,7 +1690,7 @@ explain (costs off) select * from coercepart where a = all ('{ab}'); explain (costs off) select * from coercepart where a = all ('{ab,bc}'); QUERY PLAN ------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Dynamic Seq Scan on coercepart Number of partitions to scan: 2 (out of 3) Filter: ((a)::text = ALL ('{ab,bc}'::text[])) @@ -3894,7 +3894,7 @@ explain (costs off) select * from pp_arrpart where a = '{1, 2}'; explain (costs off) select * from pp_arrpart where a in ('{4, 5}', '{1}'); QUERY PLAN ---------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Dynamic Seq Scan on pp_arrpart Number of partitions to scan: 2 (out of 2) Filter: ((a = '{4,5}'::integer[]) OR (a = '{1}'::integer[])) diff --git a/contrib/pax_storage/src/test/regress/expected/qp_misc_jiras_optimizer.out b/contrib/pax_storage/src/test/regress/expected/qp_misc_jiras_optimizer.out index 3cad459b8e7..e9e1dc84a64 100644 --- a/contrib/pax_storage/src/test/regress/expected/qp_misc_jiras_optimizer.out +++ b/contrib/pax_storage/src/test/regress/expected/qp_misc_jiras_optimizer.out @@ -5635,7 +5635,7 @@ explain select b from epsilon_test where b in (11,30) limit 30; QUERY PLAN -------------------------------------------------------------------------------------- Limit (cost=0.00..8771.18 rows=10 width=2) - -> Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..8771.18 rows=30 width=2) + -> Gather Motion 2:1 (slice1; segments: 2) (cost=0.00..8771.18 rows=30 width=2) -> Limit (cost=0.00..8771.18 rows=10 width=2) -> Seq Scan on epsilon_test (cost=0.00..8771.18 rows=10677 width=2) Filter: (b = ANY ('{11,30}'::integer[])) diff --git a/src/backend/gpopt/gpdbwrappers.cpp b/src/backend/gpopt/gpdbwrappers.cpp index 357417354e7..70abe6c72b9 100644 --- a/src/backend/gpopt/gpdbwrappers.cpp +++ b/src/backend/gpopt/gpdbwrappers.cpp @@ -1204,6 +1204,17 @@ gpdb::LAppendInt(List *list, int iDatum) return NIL; } +List * +gpdb::LAppendUniqueInt(List *list, int iDatum) +{ + GP_WRAP_START; + { + return list_append_unique_int(list, iDatum); + } + GP_WRAP_END; + return NIL; +} + List * gpdb::LAppendOid(List *list, Oid datum) { diff --git a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp index 3abfd5fed5a..07f61a74c98 100644 --- a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp +++ b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp @@ -5530,9 +5530,6 @@ CTranslatorDXLToPlStmt::TranslateDXLDirectDispatchInfo( return NIL; } - CDXLDatumArray *dxl_datum_array = (*dispatch_identifier_datum_arrays)[0]; - GPOS_ASSERT(0 < dxl_datum_array->Size()); - const ULONG length = dispatch_identifier_datum_arrays->Size(); if (dxl_direct_dispatch_info->FContainsRawValues()) @@ -5568,23 +5565,29 @@ CTranslatorDXLToPlStmt::TranslateDXLDirectDispatchInfo( return segids_list; } - ULONG hash_code = GetDXLDatumGPDBHash(dxl_datum_array, pRTEHashFuncCal); + // Each datum array is one value combination of the distribution key + // (e.g. one array per IN-list constant). Dispatch to the union of the + // segments they hash to, like the planner does. + List *segids_list = NIL; for (ULONG ul = 0; ul < length; ul++) { CDXLDatumArray *dispatch_identifier_datum_array = (*dispatch_identifier_datum_arrays)[ul]; GPOS_ASSERT(0 < dispatch_identifier_datum_array->Size()); - ULONG hash_code_new = GetDXLDatumGPDBHash( - dispatch_identifier_datum_array, pRTEHashFuncCal); + ULONG hash_code = GetDXLDatumGPDBHash(dispatch_identifier_datum_array, + pRTEHashFuncCal); - if (hash_code != hash_code_new) - { - // values don't hash to the same segment - return NIL; - } + segids_list = gpdb::LAppendUniqueInt(segids_list, hash_code); + } + + // a value set that spans every segment is equivalent to not direct + // dispatching at all + if (gpdb::ListLength(segids_list) == m_num_of_segments) + { + gpdb::ListFree(segids_list); + return NIL; } - List *segids_list = gpdb::LAppendInt(NIL, hash_code); return segids_list; } diff --git a/src/include/gpopt/gpdbwrappers.h b/src/include/gpopt/gpdbwrappers.h index 693fbdac678..760bd770265 100644 --- a/src/include/gpopt/gpdbwrappers.h +++ b/src/include/gpopt/gpdbwrappers.h @@ -456,6 +456,9 @@ List *LAppend(List *list, void *datum); // append an integer to a list List *LAppendInt(List *list, int datum); +// append an integer to a list if it is not already a member +List *LAppendUniqueInt(List *list, int datum); + // append an oid to a list List *LAppendOid(List *list, Oid datum); diff --git a/src/test/regress/expected/bfv_dd_optimizer.out b/src/test/regress/expected/bfv_dd_optimizer.out index deadff501d5..224d386ad0d 100644 --- a/src/test/regress/expected/bfv_dd_optimizer.out +++ b/src/test/regress/expected/bfv_dd_optimizer.out @@ -88,7 +88,7 @@ INFO: (slice 1) Dispatch command to SINGLE content -- single column distr key select * from dd_singlecol_1 where a in (10,11,12); -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 a | b ----+---- 10 | 10 @@ -97,7 +97,7 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 (3 rows) select * from dd_singlecol_1 where a=10 or a=11 or a=12; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 a | b ----+---- 10 | 10 @@ -106,7 +106,7 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 (3 rows) select * from dd_singlecol_1 where a is null or a=1; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 a | b ---+--- 1 | 1 @@ -115,7 +115,7 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 -- projections and disjunction select b from dd_singlecol_1 where a=1 or a=2; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 b --- 1 @@ -175,7 +175,7 @@ INFO: (slice 0) Dispatch command to SINGLE content INFO: Distributed transaction command 'Distributed Commit (one-phase)' to SINGLE content -- disjunction with partitioned tables select * from dd_part_singlecol where a in (10,11,12); -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 a | b | c ----+----+---- 10 | 20 | 30 @@ -184,7 +184,7 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 (3 rows) select * from dd_part_singlecol where a=10 or a=11 or a=12; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 a | b | c ----+----+---- 10 | 20 | 30 @@ -193,7 +193,7 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 (3 rows) select * from dd_part_singlecol where a is null or a=1; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 a | b | c ---+---+--- | | @@ -321,21 +321,21 @@ analyze dd_singlecol_idx2; INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 -- disjunction with index scans select * from dd_singlecol_idx where (a=1 or a=2) and b<2; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 a | b | c ---+---+--- 1 | 1 | 1 (1 row) select 'one' from dd_singlecol_idx where (a=1 or a=2) and b=1; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 ?column? ---------- one (1 row) select a, count(*) from dd_singlecol_idx where (a=1 or a=2) and b=1 group by a; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 a | count ---+------- 1 | 1 @@ -369,21 +369,21 @@ analyze dd_singlecol_bitmap_idx; INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 -- disjunction with bitmap index scans select * from dd_singlecol_bitmap_idx where (a=1 or a=2) and b<2; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 a | b | c ---+---+--- 1 | 1 | 1 (1 row) select * from dd_singlecol_bitmap_idx where (a=1 or a=2) and b=2 and c=2; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 a | b | c ---+---+--- 2 | 2 | 2 (1 row) select * from dd_singlecol_bitmap_idx where (a=1 or a=2) and (b=2 or c=2); -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 1 0 a | b | c ---+---+--- 2 | 2 | 2 diff --git a/src/test/regress/expected/create_index_optimizer.out b/src/test/regress/expected/create_index_optimizer.out index 7d95dd808ca..8e744326dbe 100644 --- a/src/test/regress/expected/create_index_optimizer.out +++ b/src/test/regress/expected/create_index_optimizer.out @@ -2017,7 +2017,7 @@ WHERE unique1 IN (1,42,7) ORDER BY unique1; QUERY PLAN ------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) Merge Key: unique1 -> Index Only Scan using tenk1_unique1 on tenk1 Index Cond: (unique1 = ANY ('{1,42,7}'::integer[])) diff --git a/src/test/regress/expected/direct_dispatch_optimizer.out b/src/test/regress/expected/direct_dispatch_optimizer.out index 2da45e7955a..ef3214de5bc 100644 --- a/src/test/regress/expected/direct_dispatch_optimizer.out +++ b/src/test/regress/expected/direct_dispatch_optimizer.out @@ -1130,14 +1130,14 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 explain (costs off) select gp_segment_id, * from t1_varchar where col1_varchar in ('a','b'); QUERY PLAN ---------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Seq Scan on t1_varchar Filter: ((col1_varchar)::text = ANY ('{a,b}'::text[])) Optimizer: Pivotal Optimizer (GPORCA) (4 rows) select gp_segment_id, * from t1_varchar where col1_varchar in ('a','b'); -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 gp_segment_id | col1_varchar | col2_int ---------------+--------------+---------- 1 | b | 2 @@ -1147,14 +1147,14 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 explain (costs off) select gp_segment_id, * from t1_varchar where col1_varchar = 'a' or col1_varchar = 'b'; QUERY PLAN -------------------------------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Seq Scan on t1_varchar Filter: (((col1_varchar)::text = 'a'::text) OR ((col1_varchar)::text = 'b'::text)) Optimizer: Pivotal Optimizer (GPORCA) (4 rows) select gp_segment_id, * from t1_varchar where col1_varchar = 'a' or col1_varchar = 'b'; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 gp_segment_id | col1_varchar | col2_int ---------------+--------------+---------- 1 | b | 2 @@ -1214,14 +1214,14 @@ INFO: (slice 1) Dispatch command to SINGLE content explain (costs off) select gp_segment_id, * from t1_varchar where col1_varchar in ('a', 'b') and col2_int=2; QUERY PLAN ------------------------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Seq Scan on t1_varchar Filter: (((col1_varchar)::text = ANY ('{a,b}'::text[])) AND (col2_int = 2)) Optimizer: Pivotal Optimizer (GPORCA) (4 rows) select gp_segment_id, * from t1_varchar where col1_varchar in ('a', 'b') and col2_int=2; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 gp_segment_id | col1_varchar | col2_int ---------------+--------------+---------- 1 | b | 2 @@ -1230,14 +1230,14 @@ INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 explain (costs off) select gp_segment_id, * from t1_varchar where (col1_varchar = 'a' or col1_varchar = 'b') and col2_int=1; QUERY PLAN ----------------------------------------------------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Seq Scan on t1_varchar Filter: ((((col1_varchar)::text = 'a'::text) OR ((col1_varchar)::text = 'b'::text)) AND (col2_int = 1)) Optimizer: Pivotal Optimizer (GPORCA) (4 rows) select gp_segment_id, * from t1_varchar where (col1_varchar = 'a' or col1_varchar = 'b') and col2_int=1; -INFO: (slice 1) Dispatch command to ALL contents: 0 1 2 +INFO: (slice 1) Dispatch command to PARTIAL contents: 2 1 gp_segment_id | col1_varchar | col2_int ---------------+--------------+---------- 2 | a | 1 diff --git a/src/test/regress/expected/inherit_optimizer.out b/src/test/regress/expected/inherit_optimizer.out index d30430b5519..63d6311e50b 100644 --- a/src/test/regress/expected/inherit_optimizer.out +++ b/src/test/regress/expected/inherit_optimizer.out @@ -2109,7 +2109,7 @@ explain (costs off) select * from list_parted where a is not null; explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef'); QUERY PLAN ---------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Dynamic Seq Scan on list_parted Number of partitions to scan: 2 (out of 3) Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[])) @@ -2119,7 +2119,7 @@ explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef'); explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd'); QUERY PLAN --------------------------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Dynamic Seq Scan on list_parted Number of partitions to scan: 1 (out of 3) Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[]))) @@ -2569,7 +2569,7 @@ explain (costs off) select * from mclparted order by a; explain (costs off) select * from mclparted where a in(3,4,5) order by a; QUERY PLAN ---------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) Merge Key: a -> Sort Sort Key: a @@ -2586,7 +2586,7 @@ create table mclparted_def partition of mclparted default; explain (costs off) select * from mclparted where a in(1,2,4) order by a; QUERY PLAN ---------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) Merge Key: a -> Sort Sort Key: a @@ -2599,7 +2599,7 @@ explain (costs off) select * from mclparted where a in(1,2,4) order by a; explain (costs off) select * from mclparted where a in(1,2,4) or a is null order by a; QUERY PLAN ------------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) Merge Key: a -> Sort Sort Key: a @@ -2616,7 +2616,7 @@ create table mclparted_0_null partition of mclparted for values in(0,null); explain (costs off) select * from mclparted where a in(1,2,4) or a is null order by a; QUERY PLAN ------------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) Merge Key: a -> Sort Sort Key: a @@ -2629,7 +2629,7 @@ explain (costs off) select * from mclparted where a in(1,2,4) or a is null order explain (costs off) select * from mclparted where a in(0,1,2,4) order by a; QUERY PLAN ---------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) Merge Key: a -> Sort Sort Key: a @@ -2643,7 +2643,7 @@ explain (costs off) select * from mclparted where a in(0,1,2,4) order by a; explain (costs off) select * from mclparted where a in(1,2,4) order by a; QUERY PLAN ---------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) Merge Key: a -> Sort Sort Key: a diff --git a/src/test/regress/expected/partition_append.out b/src/test/regress/expected/partition_append.out index 9154c7d5a6b..8f7209bb950 100755 --- a/src/test/regress/expected/partition_append.out +++ b/src/test/regress/expected/partition_append.out @@ -6499,7 +6499,7 @@ HINT: For non-partitioned tables, run analyze (). For QUERY PLAN -------------------------------------------------------------------------------------------------------- Finalize Aggregate - -> Gather Motion 3:1 (slice1; segments: 3) + -> Gather Motion 2:1 (slice1; segments: 2) -> Partial Aggregate -> Append -> Seq Scan on test_rangepartition_1_prt_pn_20221022 diff --git a/src/test/regress/expected/partition_optimizer.out b/src/test/regress/expected/partition_optimizer.out index c237e41bcad..a69f46baa6a 100755 --- a/src/test/regress/expected/partition_optimizer.out +++ b/src/test/regress/expected/partition_optimizer.out @@ -6425,7 +6425,7 @@ HINT: For non-partitioned tables, run analyze (). For QUERY PLAN -------------------------------------------------------------------------------------------------- Finalize Aggregate - -> Gather Motion 3:1 (slice1; segments: 3) + -> Gather Motion 2:1 (slice1; segments: 2) -> Partial Aggregate -> Dynamic Seq Scan on test_rangepartition Number of partitions to scan: 2 (out of 3) diff --git a/src/test/regress/expected/partition_prune_append.out b/src/test/regress/expected/partition_prune_append.out index 20730d90d0f..e6e6a9a5746 100644 --- a/src/test/regress/expected/partition_prune_append.out +++ b/src/test/regress/expected/partition_prune_append.out @@ -1338,7 +1338,7 @@ create table coercepart_cd partition of coercepart for values in ('cd'); explain (costs off) select * from coercepart where a in ('ab', to_char(125, '999')); QUERY PLAN ----------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Append -> Seq Scan on coercepart_ab Filter: ((a)::text = ANY ('{ab," 125"}'::text[])) @@ -1404,7 +1404,7 @@ explain (costs off) select * from coercepart where a !~ all ('{ab,bc}'); explain (costs off) select * from coercepart where a = any ('{ab,bc}'); QUERY PLAN ------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Append -> Seq Scan on coercepart_ab Filter: ((a)::text = ANY ('{ab,bc}'::text[])) @@ -1450,7 +1450,7 @@ explain (costs off) select * from coercepart where a = all ('{ab}'); explain (costs off) select * from coercepart where a = all ('{ab,bc}'); QUERY PLAN ------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Append -> Seq Scan on coercepart_ab Filter: ((a)::text = ALL ('{ab,bc}'::text[])) @@ -3455,7 +3455,7 @@ explain (costs off) select * from pp_arrpart where a = '{1, 2}'; explain (costs off) select * from pp_arrpart where a in ('{4, 5}', '{1}'); QUERY PLAN ---------------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Append -> Seq Scan on pp_arrpart1 Filter: ((a = '{4,5}'::integer[]) OR (a = '{1}'::integer[])) diff --git a/src/test/regress/expected/partition_prune_optimizer.out b/src/test/regress/expected/partition_prune_optimizer.out index 72caa769ea3..befcc41a8d4 100644 --- a/src/test/regress/expected/partition_prune_optimizer.out +++ b/src/test/regress/expected/partition_prune_optimizer.out @@ -1610,7 +1610,7 @@ create table coercepart_cd partition of coercepart for values in ('cd'); explain (costs off) select * from coercepart where a in ('ab', to_char(125, '999')); QUERY PLAN ----------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Dynamic Seq Scan on coercepart Number of partitions to scan: 1 (out of 3) Filter: ((a)::text = ANY ('{ab," 125"}'::text[])) @@ -1660,7 +1660,7 @@ explain (costs off) select * from coercepart where a !~ all ('{ab,bc}'); explain (costs off) select * from coercepart where a = any ('{ab,bc}'); QUERY PLAN ------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Dynamic Seq Scan on coercepart Number of partitions to scan: 2 (out of 3) Filter: ((a)::text = ANY ('{ab,bc}'::text[])) @@ -1700,7 +1700,7 @@ explain (costs off) select * from coercepart where a = all ('{ab}'); explain (costs off) select * from coercepart where a = all ('{ab,bc}'); QUERY PLAN ------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Dynamic Seq Scan on coercepart Number of partitions to scan: 2 (out of 3) Filter: ((a)::text = ALL ('{ab,bc}'::text[])) @@ -3904,7 +3904,7 @@ explain (costs off) select * from pp_arrpart where a = '{1, 2}'; explain (costs off) select * from pp_arrpart where a in ('{4, 5}', '{1}'); QUERY PLAN ---------------------------------------------------------------------- - Gather Motion 3:1 (slice1; segments: 3) + Gather Motion 2:1 (slice1; segments: 2) -> Dynamic Seq Scan on pp_arrpart Number of partitions to scan: 2 (out of 2) Filter: ((a = '{4,5}'::integer[]) OR (a = '{1}'::integer[])) diff --git a/src/test/regress/expected/qp_misc_jiras_optimizer.out b/src/test/regress/expected/qp_misc_jiras_optimizer.out index 084c4ddb34b..fd70b270c54 100644 --- a/src/test/regress/expected/qp_misc_jiras_optimizer.out +++ b/src/test/regress/expected/qp_misc_jiras_optimizer.out @@ -5634,7 +5634,7 @@ explain select b from epsilon_test where b in (11,30) limit 30; QUERY PLAN -------------------------------------------------------------------------------------- Limit (cost=0.00..8771.18 rows=10 width=2) - -> Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..8771.18 rows=30 width=2) + -> Gather Motion 2:1 (slice1; segments: 2) (cost=0.00..8771.18 rows=30 width=2) -> Limit (cost=0.00..8771.18 rows=10 width=2) -> Seq Scan on epsilon_test (cost=0.00..8771.18 rows=10677 width=2) Filter: (b = ANY ('{11,30}'::integer[]))