//--------------------------------------------------------------------------- // @function: // CJoinOrderDP::PexprBuildPred // // @doc: // Build predicate connecting the two given sets // //--------------------------------------------------------------------------- CExpression * CJoinOrderDP::PexprBuildPred ( CBitSet *pbsFst, CBitSet *pbsSnd ) { // collect edges connecting the given sets CBitSet *pbsEdges = GPOS_NEW(m_mp) CBitSet(m_mp); CBitSet *pbs = GPOS_NEW(m_mp) CBitSet(m_mp, *pbsFst); pbs->Union(pbsSnd); for (ULONG ul = 0; ul < m_ulEdges; ul++) { SEdge *pedge = m_rgpedge[ul]; if ( pbs->ContainsAll(pedge->m_pbs) && !pbsFst->IsDisjoint(pedge->m_pbs) && !pbsSnd->IsDisjoint(pedge->m_pbs) ) { #ifdef GPOS_DEBUG BOOL fSet = #endif // GPOS_DEBUG pbsEdges->ExchangeSet(ul); GPOS_ASSERT(!fSet); } } pbs->Release(); CExpression *pexprPred = NULL; if (0 < pbsEdges->Size()) { CExpressionArray *pdrgpexpr = GPOS_NEW(m_mp) CExpressionArray(m_mp); CBitSetIter bsi(*pbsEdges); while (bsi.Advance()) { ULONG ul = bsi.Bit(); SEdge *pedge = m_rgpedge[ul]; pedge->m_pexpr->AddRef(); pdrgpexpr->Append(pedge->m_pexpr); } pexprPred = CPredicateUtils::PexprConjunction(m_mp, pdrgpexpr); } pbsEdges->Release(); return pexprPred; }
//--------------------------------------------------------------------------- // @function: // CPhysical::PppsRequiredPushThruNAry // // @doc: // Helper for pushing required partition propagation to the children of // an n-ary operator // //--------------------------------------------------------------------------- CPartitionPropagationSpec * CPhysical::PppsRequiredPushThruNAry ( IMemoryPool *mp, CExpressionHandle &exprhdl, CPartitionPropagationSpec *pppsReqd, ULONG child_index ) { GPOS_ASSERT(NULL != pppsReqd); CPartIndexMap *ppimReqd = pppsReqd->Ppim(); CPartFilterMap *ppfmReqd = pppsReqd->Ppfm(); ULongPtrArray *pdrgpul = ppimReqd->PdrgpulScanIds(mp); CPartIndexMap *ppimResult = GPOS_NEW(mp) CPartIndexMap(mp); CPartFilterMap *ppfmResult = GPOS_NEW(mp) CPartFilterMap(mp); const ULONG ulPartIndexIds = pdrgpul->Size(); const ULONG arity = exprhdl.UlNonScalarChildren(); // iterate over required part index ids and decide which ones to push to the outer // and which to the inner side of the n-ary op for (ULONG ul = 0; ul < ulPartIndexIds; ul++) { ULONG part_idx_id = *((*pdrgpul)[ul]); GPOS_ASSERT(ppimReqd->Contains(part_idx_id)); CBitSet *pbsPartConsumer = GPOS_NEW(mp) CBitSet(mp); for (ULONG ulChildIdx = 0; ulChildIdx < arity; ulChildIdx++) { if (exprhdl.GetRelationalProperties(ulChildIdx)->Ppartinfo()->FContainsScanId(part_idx_id)) { (void) pbsPartConsumer->ExchangeSet(ulChildIdx); } } if (arity == pbsPartConsumer->Size() && COperator::EopPhysicalSequence == exprhdl.Pop()->Eopid() && (*(exprhdl.Pgexpr()))[0]->FHasCTEProducer()) { GPOS_ASSERT(2 == arity); // this is a part index id that comes from both sides of a sequence // with a CTE producer on the outer side, so pretend that part index // id is not defined the inner sides pbsPartConsumer->ExchangeClear(1); } if (!FCanPushPartReqToChild(pbsPartConsumer, child_index)) { // clean up pbsPartConsumer->Release(); continue; } // clean up pbsPartConsumer->Release(); CPartKeysArray *pdrgppartkeys = exprhdl.GetRelationalProperties(child_index)->Ppartinfo()->PdrgppartkeysByScanId(part_idx_id); GPOS_ASSERT(NULL != pdrgppartkeys); pdrgppartkeys->AddRef(); // push requirements to child node ppimResult->AddRequiredPartPropagation(ppimReqd, part_idx_id, CPartIndexMap::EppraPreservePropagators, pdrgppartkeys); // check if there is a filter on the part index id and propagate that further down if (ppfmReqd->FContainsScanId(part_idx_id)) { CExpression *pexpr = ppfmReqd->Pexpr(part_idx_id); // if the current child is inner child and the predicate is IsNull check and the parent is outer join, // don't push IsNull check predicate to the partition filter. // for all the other cases, push the filter down. if (!(1 == child_index && CUtils::FScalarNullTest(pexpr) && CUtils::FPhysicalOuterJoin(exprhdl.Pop())) ) { pexpr->AddRef(); ppfmResult->AddPartFilter(mp, part_idx_id, pexpr, NULL /*stats */); } } } pdrgpul->Release(); return GPOS_NEW(mp) CPartitionPropagationSpec(ppimResult, ppfmResult); }
//--------------------------------------------------------------------------- // @function: // CJoinOrderDP::PexprBestJoinOrder // // @doc: // find best join order for a given set of elements; // //--------------------------------------------------------------------------- CExpression * CJoinOrderDP::PexprBestJoinOrder ( CBitSet *pbs ) { GPOS_CHECK_STACK_SIZE; GPOS_CHECK_ABORT; GPOS_ASSERT(NULL != pbs); // start by looking-up cost in the DP map CExpression *pexpr = PexprLookup(pbs); if (pexpr == m_pexprDummy) { // no join order could be created return NULL; } if (NULL != pexpr) { // join order is found by looking up map return pexpr; } // find maximal covered subset CBitSet *pbsCovered = PbsCovered(pbs); if (0 == pbsCovered->Size()) { // set is not covered, return a cross product pbsCovered->Release(); return PexprCross(pbs); } if (!pbsCovered->Equals(pbs)) { // create a cross product for uncovered subset CBitSet *pbsUncovered = GPOS_NEW(m_mp) CBitSet(m_mp, *pbs); pbsUncovered->Difference(pbsCovered); CExpression *pexprResult = PexprJoinCoveredSubsetWithUncoveredSubset(pbs, pbsCovered, pbsUncovered); pbsCovered->Release(); pbsUncovered->Release(); return pexprResult; } pbsCovered->Release(); // if set has size 2, there is only one possible solution if (2 == pbs->Size()) { return PexprJoin(pbs); } // otherwise, compute best join order using dynamic programming CExpression *pexprBestJoinOrder = PexprBestJoinOrderDP(pbs); if (pexprBestJoinOrder == m_pexprDummy) { // no join order could be created return NULL; } return pexprBestJoinOrder; }