From aee855135c670b02a81d04cc792b47910ffd80a5 Mon Sep 17 00:00:00 2001 From: WANG Weinan Date: Fri, 28 Nov 2025 18:37:38 +0800 Subject: [PATCH] Remove redundent Shared Scan after dedup subquery After subquery dedup(ref. a031a4a9485defcc6b9234986d824fe62fa25641), The cte consumer need to decrement, so that XformInlineCTE can help us rid of unnecessary Shared Scan node. TODO: 1. Instead of mock CTE MDID, we should parser CTE related relation MDID, and dedup CTE with other flat subquery together. 2. inner join subquery, join order should not involve into dedup comparation 3. For subquery, not only AndOp but also OrOp can dedup --- .../libgpopt/include/gpopt/base/CCTEInfo.h | 13 + .../gporca/libgpopt/src/base/CCTEInfo.cpp | 22 ++ .../operators/CDedupSupersetPreprocessor.cpp | 21 +- .../regress/expected/dedupset_optimizer.out | 304 ++++++++---------- 4 files changed, 186 insertions(+), 174 deletions(-) diff --git a/src/backend/gporca/libgpopt/include/gpopt/base/CCTEInfo.h b/src/backend/gporca/libgpopt/include/gpopt/base/CCTEInfo.h index bf72a444734..07d5f40c51d 100644 --- a/src/backend/gporca/libgpopt/include/gpopt/base/CCTEInfo.h +++ b/src/backend/gporca/libgpopt/include/gpopt/base/CCTEInfo.h @@ -84,6 +84,15 @@ class CCTEInfo : public CRefCount { m_ulCount++; } + + void + Decrement() + { + GPOS_ASSERT(m_ulCount > 1); + m_ulCount--; + GPOS_ASSERT(m_ulCount > 0); + } + }; // hash map mapping ULONG -> SConsumerCounter @@ -283,6 +292,10 @@ class CCTEInfo : public CRefCount void IncrementConsumers(ULONG ulConsumerId, ULONG ulParentCTEId = gpos::ulong_max); + // decrement number of CTE consumers + void DecrementConsumers(ULONG ulConsumerId, + ULONG ulParentCTEId = gpos::ulong_max); + // add cte producer to hashmap void AddCTEProducer(CExpression *pexprCTEProducer); diff --git a/src/backend/gporca/libgpopt/src/base/CCTEInfo.cpp b/src/backend/gporca/libgpopt/src/base/CCTEInfo.cpp index b6423c0073f..5d0521bf11c 100644 --- a/src/backend/gporca/libgpopt/src/base/CCTEInfo.cpp +++ b/src/backend/gporca/libgpopt/src/base/CCTEInfo.cpp @@ -561,6 +561,28 @@ CCTEInfo::IncrementConsumers(ULONG ulConsumerId, ULONG ulParentCTEId) } } +//--------------------------------------------------------------------------- +// @function: +// CCTEInfo::IncrementConsumers +// +// @doc: +// Decrement number of CTE consumers +// +//--------------------------------------------------------------------------- +void +CCTEInfo::DecrementConsumers(ULONG ulConsumerId, ULONG ulParentCTEId) +{ + UlongToConsumerCounterMap *phmulconsumermap = + m_phmulprodconsmap->Find(&ulParentCTEId); + + GPOS_ASSERT(nullptr != phmulconsumermap); + + SConsumerCounter *pconsumercounter = phmulconsumermap->Find(&ulConsumerId); + GPOS_ASSERT(nullptr != pconsumercounter); + + pconsumercounter->Decrement(); +} + //--------------------------------------------------------------------------- // @function: diff --git a/src/backend/gporca/libgpopt/src/operators/CDedupSupersetPreprocessor.cpp b/src/backend/gporca/libgpopt/src/operators/CDedupSupersetPreprocessor.cpp index a0678af79ab..faa179462a3 100644 --- a/src/backend/gporca/libgpopt/src/operators/CDedupSupersetPreprocessor.cpp +++ b/src/backend/gporca/libgpopt/src/operators/CDedupSupersetPreprocessor.cpp @@ -156,7 +156,8 @@ CDedupSupersetPreprocessor::ChildExprFullSuperset(CMemoryPool *mp, } CColRefSet *colrefsets = pexpr_child0->DeriveOutputColumns(); - // The colref(in CScalarSubqueryAny) must in the output + // The colref(in CScalarSubqueryAny) must in the output + // FIXME: do not use index, it does not follow ORCA design principle (void) colrefsets->ExtractIndex(pop_subany->Pcr(), &ulidx_subany); GPOS_ASSERT(ulidx_subany != gpos::ulong_max); @@ -519,6 +520,23 @@ CDedupSupersetPreprocessor::PexprPreprocess(CMemoryPool *mp, CExpression *pexpr) { if (!dedupulmasks[ul]) { + if (COperator::EopScalarSubqueryAny == (*pexpr)[ul]->Pop()->Eopid()) + { + CExpression *pdrgpexprSubqueryAny = (*pexpr)[ul]; + CExpression *pdrgpexpr = (*pdrgpexprSubqueryAny)[0]; + + // remove the CTE consumer from CTEINFO + if (COperator::EopLogicalCTEConsumer == pdrgpexpr->Pop()->Eopid()) + { + CCTEInfo *pcteinfo = + COptCtxt::PoctxtFromTLS()->Pcteinfo(); + CLogicalCTEConsumer *pop = + CLogicalCTEConsumer::PopConvert(pdrgpexpr->Pop()); + + pcteinfo->DecrementConsumers(pop->UlCTEId()); + } + } + continue; } @@ -534,7 +552,6 @@ CDedupSupersetPreprocessor::PexprPreprocess(CMemoryPool *mp, CExpression *pexpr) return GPOS_NEW(mp) CExpression(mp, pop, pdrgpexprChildren); } - // FIXME: should we consider remove the CTE consumer from CTEINFO? const ULONG arity = pexpr->Arity(); CExpressionArray *pdrgpexprChildren = GPOS_NEW(mp) CExpressionArray(mp); diff --git a/src/test/regress/expected/dedupset_optimizer.out b/src/test/regress/expected/dedupset_optimizer.out index f9369e5a87f..a11bb4f88fc 100644 --- a/src/test/regress/expected/dedupset_optimizer.out +++ b/src/test/regress/expected/dedupset_optimizer.out @@ -196,44 +196,32 @@ select * from pt1 where v1 in (select v3 from pt2 where v3 < 10); (9 rows) explain verbose with cte1 as (select v3 from t2) select count(*) from t1,t2 where t1.v1 in (select v3 from cte1) and t1.v1 in (select v3 from cte1 where v3 < 10); - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ - Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..1324954.52 rows=1 width=8) - Output: (count(*)) - -> Sequence (cost=0.00..1324954.52 rows=1 width=8) - Output: (count(*)) - -> Shared Scan (share slice:id 1:0) (cost=0.00..431.00 rows=34 width=1) - Output: share0_ref1.v3 - -> Seq Scan on public.t2 (cost=0.00..431.00 rows=34 width=4) - Output: t2.v3 - -> Redistribute Motion 1:3 (slice2) (cost=0.00..1324523.52 rows=1 width=8) - Output: (count(*)) - -> Finalize Aggregate (cost=0.00..1324523.52 rows=1 width=8) - Output: count(*) - -> Gather Motion 3:1 (slice3; segments: 3) (cost=0.00..1324523.52 rows=1 width=8) - Output: (PARTIAL count(*)) - -> Partial Aggregate (cost=0.00..1324523.52 rows=1 width=8) - Output: PARTIAL count(*) - -> Hash Semi Join (cost=0.00..1324523.52 rows=304 width=1) - Hash Cond: (t1.v1 = share0_ref2.v3) - -> Nested Loop (cost=0.00..1324091.93 rows=3334 width=4) - Output: t1.v1 - Join Filter: true - -> Seq Scan on public.t1 (cost=0.00..431.00 rows=34 width=4) - Output: t1.v1 - -> Materialize (cost=0.00..431.00 rows=100 width=1) - -> Broadcast Motion 3:3 (slice4; segments: 3) (cost=0.00..431.00 rows=100 width=1) - -> Seq Scan on public.t2 t2_1 (cost=0.00..431.00 rows=34 width=1) - -> Hash (cost=431.00..431.00 rows=4 width=4) - Output: share0_ref2.v3 - -> Result (cost=0.00..431.00 rows=4 width=4) - Output: share0_ref2.v3 - Filter: (share0_ref2.v3 < 10) - -> Shared Scan (share slice:id 3:0) (cost=0.00..431.00 rows=34 width=4) - Output: share0_ref2.v3 + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- + Finalize Aggregate (cost=0.00..1324523.52 rows=1 width=8) + Output: count(*) + -> Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..1324523.52 rows=1 width=8) + Output: (PARTIAL count(*)) + -> Partial Aggregate (cost=0.00..1324523.51 rows=1 width=8) + Output: PARTIAL count(*) + -> Hash Semi Join (cost=0.00..1324523.51 rows=304 width=1) + Hash Cond: (t1.v1 = t2_1.v3) + -> Nested Loop (cost=0.00..1324091.93 rows=3334 width=4) + Output: t1.v1 + Join Filter: true + -> Seq Scan on public.t1 (cost=0.00..431.00 rows=34 width=4) + Output: t1.v1 + -> Materialize (cost=0.00..431.00 rows=100 width=1) + -> Broadcast Motion 3:3 (slice2; segments: 3) (cost=0.00..431.00 rows=100 width=1) + -> Seq Scan on public.t2 (cost=0.00..431.00 rows=34 width=1) + -> Hash (cost=431.00..431.00 rows=4 width=4) + Output: t2_1.v3 + -> Seq Scan on public.t2 t2_1 (cost=0.00..431.00 rows=4 width=4) + Output: t2_1.v3 + Filter: (t2_1.v3 < 10) Settings: enable_parallel = 'off', optimizer = 'on' Optimizer: GPORCA -(35 rows) +(23 rows) explain verbose with cte1 as (select v3 from t2) select count(*) from t1,t2 where t1.v1 in (select v3 from cte1 where v3 < 10); QUERY PLAN @@ -635,41 +623,31 @@ select count(*) from pt1 where v1 in (select v3 from pt2); (1 row) explain verbose with cte1 as (select v3 from t2) select count(*) from t1,t2 where t1.v1 in (select v3 from cte1) and t1.v1 in (select v3 from cte1); - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ - Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..1324954.53 rows=1 width=8) - Output: (count(*)) - -> Sequence (cost=0.00..1324954.53 rows=1 width=8) - Output: (count(*)) - -> Shared Scan (share slice:id 1:0) (cost=0.00..431.00 rows=34 width=1) - Output: share0_ref1.v3 - -> Seq Scan on public.t2 (cost=0.00..431.00 rows=34 width=4) - Output: t2.v3 - -> Redistribute Motion 1:3 (slice2) (cost=0.00..1324523.53 rows=1 width=8) - Output: (count(*)) - -> Finalize Aggregate (cost=0.00..1324523.53 rows=1 width=8) - Output: count(*) - -> Gather Motion 3:1 (slice3; segments: 3) (cost=0.00..1324523.53 rows=1 width=8) - Output: (PARTIAL count(*)) - -> Partial Aggregate (cost=0.00..1324523.53 rows=1 width=8) - Output: PARTIAL count(*) - -> Hash Semi Join (cost=0.00..1324523.53 rows=3334 width=1) - Hash Cond: (t1.v1 = share0_ref2.v3) - -> Nested Loop (cost=0.00..1324091.93 rows=3334 width=4) - Output: t1.v1 - Join Filter: true - -> Seq Scan on public.t1 (cost=0.00..431.00 rows=34 width=4) - Output: t1.v1 - -> Materialize (cost=0.00..431.00 rows=100 width=1) - -> Broadcast Motion 3:3 (slice4; segments: 3) (cost=0.00..431.00 rows=100 width=1) - -> Seq Scan on public.t2 t2_1 (cost=0.00..431.00 rows=34 width=1) - -> Hash (cost=431.00..431.00 rows=34 width=4) - Output: share0_ref2.v3 - -> Shared Scan (share slice:id 3:0) (cost=0.00..431.00 rows=34 width=4) - Output: share0_ref2.v3 + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- + Finalize Aggregate (cost=0.00..1324523.53 rows=1 width=8) + Output: count(*) + -> Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..1324523.53 rows=1 width=8) + Output: (PARTIAL count(*)) + -> Partial Aggregate (cost=0.00..1324523.53 rows=1 width=8) + Output: PARTIAL count(*) + -> Hash Semi Join (cost=0.00..1324523.53 rows=3334 width=1) + Hash Cond: (t1.v1 = t2_1.v3) + -> Nested Loop (cost=0.00..1324091.93 rows=3334 width=4) + Output: t1.v1 + Join Filter: true + -> Seq Scan on public.t1 (cost=0.00..431.00 rows=34 width=4) + Output: t1.v1 + -> Materialize (cost=0.00..431.00 rows=100 width=1) + -> Broadcast Motion 3:3 (slice2; segments: 3) (cost=0.00..431.00 rows=100 width=1) + -> Seq Scan on public.t2 (cost=0.00..431.00 rows=34 width=1) + -> Hash (cost=431.00..431.00 rows=34 width=4) + Output: t2_1.v3 + -> Seq Scan on public.t2 t2_1 (cost=0.00..431.00 rows=34 width=4) + Output: t2_1.v3 Settings: enable_parallel = 'off', optimizer = 'on' Optimizer: GPORCA -(32 rows) +(22 rows) explain verbose with cte1 as (select v3 from t2) select count(*) from t1,t2 where t1.v1 in (select v3 from cte1); QUERY PLAN @@ -1097,80 +1075,68 @@ select * from pt1 where v1 in (select v3 from pt2,t3 where v4=v6 and v4 < 10); (9 rows) explain verbose with cte1 as (select v3 from t2) select * from t1,t2 where t1.v1 in (select v3 from cte1) and t1.v1 in (select v3 from cte1,t3 where v4=v6); - QUERY PLAN ------------------------------------------------------------------------------------------------------------------ - Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..2648910.08 rows=5625 width=16) - Output: t1.v1, t1.v2, t2_1.v3, t2_1.v4 - -> Sequence (cost=0.00..2648909.74 rows=1875 width=16) - Output: t1.v1, t1.v2, t2_1.v3, t2_1.v4 - -> Shared Scan (share slice:id 1:0) (cost=0.00..431.00 rows=34 width=1) - Output: share0_ref1.v3 - -> Seq Scan on public.t2 (cost=0.00..431.00 rows=34 width=4) - Output: t2.v3 - -> Hash Semi Join (cost=0.00..2648478.71 rows=1875 width=16) - Output: t1.v1, t1.v2, t2_1.v3, t2_1.v4 - Hash Cond: ((t2_1.v4 = t3.v6) AND (t1.v1 = share0_ref2.v3)) - -> Nested Loop (cost=0.00..1324306.71 rows=3334 width=16) - Output: t1.v1, t1.v2, t2_1.v3, t2_1.v4 + QUERY PLAN +----------------------------------------------------------------------------------------------------------- + Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..2648479.76 rows=5625 width=16) + Output: t1.v1, t1.v2, t2.v3, t2.v4 + -> Hash Semi Join (cost=0.00..2648479.42 rows=1875 width=16) + Output: t1.v1, t1.v2, t2.v3, t2.v4 + Hash Cond: ((t2.v4 = t3.v6) AND (t1.v1 = t2_1.v3)) + -> Nested Loop (cost=0.00..1324306.71 rows=3334 width=16) + Output: t1.v1, t1.v2, t2.v3, t2.v4 + Join Filter: true + -> Broadcast Motion 3:3 (slice2; segments: 3) (cost=0.00..431.02 rows=100 width=8) + Output: t2.v3, t2.v4 + -> Seq Scan on public.t2 (cost=0.00..431.00 rows=34 width=8) + Output: t2.v3, t2.v4 + -> Seq Scan on public.t1 (cost=0.00..431.00 rows=34 width=8) + Output: t1.v1, t1.v2 + -> Hash (cost=1324170.14..1324170.14 rows=3334 width=8) + Output: t2_1.v3, t3.v6 + -> Nested Loop (cost=0.00..1324170.14 rows=3334 width=8) + Output: t2_1.v3, t3.v6 Join Filter: true - -> Broadcast Motion 3:3 (slice2; segments: 3) (cost=0.00..431.02 rows=100 width=8) - Output: t2_1.v3, t2_1.v4 - -> Seq Scan on public.t2 t2_1 (cost=0.00..431.00 rows=34 width=8) - Output: t2_1.v3, t2_1.v4 - -> Seq Scan on public.t1 (cost=0.00..431.00 rows=34 width=8) - Output: t1.v1, t1.v2 - -> Hash (cost=1324169.43..1324169.43 rows=3334 width=8) - Output: share0_ref2.v3, t3.v6 - -> Nested Loop (cost=0.00..1324169.43 rows=3334 width=8) - Output: share0_ref2.v3, t3.v6 - Join Filter: true - -> Broadcast Motion 3:3 (slice3; segments: 3) (cost=0.00..431.01 rows=100 width=4) + -> Broadcast Motion 3:3 (slice3; segments: 3) (cost=0.00..431.01 rows=100 width=4) + Output: t3.v6 + -> Seq Scan on public.t3 (cost=0.00..431.00 rows=34 width=4) Output: t3.v6 - -> Seq Scan on public.t3 (cost=0.00..431.00 rows=34 width=4) - Output: t3.v6 - -> Shared Scan (share slice:id 1:0) (cost=0.00..431.00 rows=34 width=4) - Output: share0_ref2.v3 + -> Seq Scan on public.t2 t2_1 (cost=0.00..431.00 rows=34 width=4) + Output: t2_1.v3 Settings: enable_parallel = 'off', optimizer = 'on' Optimizer: GPORCA -(33 rows) +(27 rows) explain verbose with cte1 as (select v3 from t2) select * from t1,t2 where t1.v1 in (select v3 from cte1) and t1.v1 in (select v3 from t3,cte1 where v4=v6); - QUERY PLAN ------------------------------------------------------------------------------------------------------------------ - Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..2648910.08 rows=5625 width=16) - Output: t1.v1, t1.v2, t2_1.v3, t2_1.v4 - -> Sequence (cost=0.00..2648909.74 rows=1875 width=16) - Output: t1.v1, t1.v2, t2_1.v3, t2_1.v4 - -> Shared Scan (share slice:id 1:0) (cost=0.00..431.00 rows=34 width=1) - Output: share0_ref1.v3 - -> Seq Scan on public.t2 (cost=0.00..431.00 rows=34 width=4) - Output: t2.v3 - -> Hash Semi Join (cost=0.00..2648478.71 rows=1875 width=16) - Output: t1.v1, t1.v2, t2_1.v3, t2_1.v4 - Hash Cond: ((t2_1.v4 = t3.v6) AND (t1.v1 = share0_ref2.v3)) - -> Nested Loop (cost=0.00..1324306.71 rows=3334 width=16) - Output: t1.v1, t1.v2, t2_1.v3, t2_1.v4 + QUERY PLAN +----------------------------------------------------------------------------------------------------------- + Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..2648479.76 rows=5625 width=16) + Output: t1.v1, t1.v2, t2.v3, t2.v4 + -> Hash Semi Join (cost=0.00..2648479.42 rows=1875 width=16) + Output: t1.v1, t1.v2, t2.v3, t2.v4 + Hash Cond: ((t2.v4 = t3.v6) AND (t1.v1 = t2_1.v3)) + -> Nested Loop (cost=0.00..1324306.71 rows=3334 width=16) + Output: t1.v1, t1.v2, t2.v3, t2.v4 + Join Filter: true + -> Broadcast Motion 3:3 (slice2; segments: 3) (cost=0.00..431.02 rows=100 width=8) + Output: t2.v3, t2.v4 + -> Seq Scan on public.t2 (cost=0.00..431.00 rows=34 width=8) + Output: t2.v3, t2.v4 + -> Seq Scan on public.t1 (cost=0.00..431.00 rows=34 width=8) + Output: t1.v1, t1.v2 + -> Hash (cost=1324170.14..1324170.14 rows=3334 width=8) + Output: t3.v6, t2_1.v3 + -> Nested Loop (cost=0.00..1324170.14 rows=3334 width=8) + Output: t3.v6, t2_1.v3 Join Filter: true - -> Broadcast Motion 3:3 (slice2; segments: 3) (cost=0.00..431.02 rows=100 width=8) - Output: t2_1.v3, t2_1.v4 - -> Seq Scan on public.t2 t2_1 (cost=0.00..431.00 rows=34 width=8) - Output: t2_1.v3, t2_1.v4 - -> Seq Scan on public.t1 (cost=0.00..431.00 rows=34 width=8) - Output: t1.v1, t1.v2 - -> Hash (cost=1324169.43..1324169.43 rows=3334 width=8) - Output: t3.v6, share0_ref2.v3 - -> Nested Loop (cost=0.00..1324169.43 rows=3334 width=8) - Output: t3.v6, share0_ref2.v3 - Join Filter: true - -> Broadcast Motion 3:3 (slice3; segments: 3) (cost=0.00..431.01 rows=100 width=4) + -> Broadcast Motion 3:3 (slice3; segments: 3) (cost=0.00..431.01 rows=100 width=4) + Output: t3.v6 + -> Seq Scan on public.t3 (cost=0.00..431.00 rows=34 width=4) Output: t3.v6 - -> Seq Scan on public.t3 (cost=0.00..431.00 rows=34 width=4) - Output: t3.v6 - -> Shared Scan (share slice:id 1:0) (cost=0.00..431.00 rows=34 width=4) - Output: share0_ref2.v3 + -> Seq Scan on public.t2 t2_1 (cost=0.00..431.00 rows=34 width=4) + Output: t2_1.v3 Settings: enable_parallel = 'off', optimizer = 'on' Optimizer: GPORCA -(33 rows) +(27 rows) explain verbose with cte1 as (select v3 from t2) select * from t1,t2 where t1.v1 in (select v3 from cte1,t3 where v4=v6 and v4 < 10); QUERY PLAN @@ -1212,49 +1178,43 @@ explain verbose with cte1 as (select v3 from t2) select * from t1,t2 where t1.v1 (34 rows) explain verbose with cte1 as (select v3 from t2) select * from t1,t2 where t1.v1 in (select v3 from cte1) and t1.v1 in (select v3 from cte1,t3 where v4=v6 and v4 < 10); - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ - Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..2648784.74 rows=512 width=16) - Output: t1.v1, t1.v2, t2_1.v3, t2_1.v4 - -> Sequence (cost=0.00..2648784.71 rows=171 width=16) - Output: t1.v1, t1.v2, t2_1.v3, t2_1.v4 - -> Shared Scan (share slice:id 1:0) (cost=0.00..431.00 rows=34 width=1) - Output: share0_ref1.v3 - -> Seq Scan on public.t2 (cost=0.00..431.00 rows=34 width=4) - Output: t2.v3 - -> Hash Semi Join (cost=0.00..2648353.70 rows=171 width=16) - Output: t1.v1, t1.v2, t2_1.v3, t2_1.v4 - Hash Cond: ((t2_1.v4 = t3.v6) AND (t1.v1 = share0_ref2.v3)) - -> Redistribute Motion 3:3 (slice2; segments: 3) (cost=0.00..1324306.84 rows=304 width=16) - Output: t1.v1, t1.v2, t2_1.v3, t2_1.v4 - Hash Key: t1.v1 - -> Result (cost=0.00..1324306.82 rows=304 width=16) - Output: t1.v1, t1.v2, t2_1.v3, t2_1.v4 - Filter: (t2_1.v4 < 10) - -> Nested Loop (cost=0.00..1324306.71 rows=3334 width=16) - Output: t1.v1, t1.v2, t2_1.v3, t2_1.v4 - Join Filter: true - -> Broadcast Motion 3:3 (slice3; segments: 3) (cost=0.00..431.02 rows=100 width=8) - Output: t1.v1, t1.v2 - -> Seq Scan on public.t1 (cost=0.00..431.00 rows=34 width=8) - Output: t1.v1, t1.v2 - -> Seq Scan on public.t2 t2_1 (cost=0.00..431.00 rows=34 width=8) - Output: t2_1.v3, t2_1.v4 - -> Hash (cost=1324046.63..1324046.63 rows=304 width=8) - Output: share0_ref2.v3, t3.v6 - -> Nested Loop (cost=0.00..1324046.63 rows=304 width=8) - Output: share0_ref2.v3, t3.v6 + QUERY PLAN +----------------------------------------------------------------------------------------------------------------- + Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..2648354.45 rows=512 width=16) + Output: t1.v1, t1.v2, t2.v3, t2.v4 + -> Hash Semi Join (cost=0.00..2648354.42 rows=171 width=16) + Output: t1.v1, t1.v2, t2.v3, t2.v4 + Hash Cond: ((t2.v4 = t3.v6) AND (t1.v1 = t2_1.v3)) + -> Redistribute Motion 3:3 (slice2; segments: 3) (cost=0.00..1324306.84 rows=304 width=16) + Output: t1.v1, t1.v2, t2.v3, t2.v4 + Hash Key: t1.v1 + -> Result (cost=0.00..1324306.82 rows=304 width=16) + Output: t1.v1, t1.v2, t2.v3, t2.v4 + Filter: (t2.v4 < 10) + -> Nested Loop (cost=0.00..1324306.71 rows=3334 width=16) + Output: t1.v1, t1.v2, t2.v3, t2.v4 Join Filter: true - -> Broadcast Motion 3:3 (slice4; segments: 3) (cost=0.00..431.00 rows=10 width=4) + -> Broadcast Motion 3:3 (slice3; segments: 3) (cost=0.00..431.02 rows=100 width=8) + Output: t1.v1, t1.v2 + -> Seq Scan on public.t1 (cost=0.00..431.00 rows=34 width=8) + Output: t1.v1, t1.v2 + -> Seq Scan on public.t2 (cost=0.00..431.00 rows=34 width=8) + Output: t2.v3, t2.v4 + -> Hash (cost=1324047.35..1324047.35 rows=304 width=8) + Output: t2_1.v3, t3.v6 + -> Nested Loop (cost=0.00..1324047.35 rows=304 width=8) + Output: t2_1.v3, t3.v6 + Join Filter: true + -> Broadcast Motion 3:3 (slice4; segments: 3) (cost=0.00..431.00 rows=10 width=4) + Output: t3.v6 + -> Seq Scan on public.t3 (cost=0.00..431.00 rows=4 width=4) Output: t3.v6 - -> Seq Scan on public.t3 (cost=0.00..431.00 rows=4 width=4) - Output: t3.v6 - Filter: (t3.v6 < 10) - -> Shared Scan (share slice:id 1:0) (cost=0.00..431.00 rows=34 width=4) - Output: share0_ref2.v3 + Filter: (t3.v6 < 10) + -> Seq Scan on public.t2 t2_1 (cost=0.00..431.00 rows=34 width=4) + Output: t2_1.v3 Settings: enable_parallel = 'off', optimizer = 'on' Optimizer: GPORCA -(40 rows) +(34 rows) with cte1 as (select v3 from t2) select sum(v1) from t1,t2 where t1.v1 in (select v3 from cte1) and t1.v1 in (select v3 from cte1,t3 where v4=v6 and v4 < 10); sum