diff --git a/src/jrd/optimizer/Optimizer.cpp b/src/jrd/optimizer/Optimizer.cpp index af0431b486..ebf077dc9d 100644 --- a/src/jrd/optimizer/Optimizer.cpp +++ b/src/jrd/optimizer/Optimizer.cpp @@ -174,6 +174,7 @@ namespace // Save states of the underlying streams and restore them afterwards StreamStateHolder stateHolder(csb, m_streams); + stateHolder.deactivate(); // Generate record source objects @@ -569,7 +570,6 @@ Optimizer::Optimizer(thread_db* aTdbb, CompilerScratch* aCsb, RseNode* aRse, boo compileStreams(getPool()), bedStreams(getPool()), keyStreams(getPool()), - subStreams(getPool()), outerStreams(getPool()), conjuncts(getPool()) { @@ -814,7 +814,7 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack) // Go through the record selection expression generating // record source blocks for all streams - RiverList rivers; + RiverList rivers, dependentRivers; bool innerSubStream = false; for (auto node : rse->rse_relations) @@ -840,11 +840,13 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack) StreamList localStreams; rsb->findUsedStreams(localStreams); + bool computable = false; + // AB: Save all outer-part streams if (isInnerJoin() || (isLeftJoin() && !innerSubStream)) { - subStreams.join(localStreams); - outerStreams.join(localStreams); + if (node->computable(csb, INVALID_STREAM, false)) + computable = true; // Apply local booleans, if any. Note that it's done // only for inner joins and outer streams of left joins. @@ -854,7 +856,16 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack) const auto river = FB_NEW_POOL(getPool()) River(csb, rsb, node, localStreams); river->deactivate(csb); - rivers.add(river); + + if (computable) + { + outerStreams.join(localStreams); + rivers.add(river); + } + else + { + dependentRivers.add(river); + } } else { @@ -883,9 +894,9 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack) else rse->rse_aggregate = aggregate = nullptr; - // AB: Mark the previous used streams (sub-RseNode's) as active - for (const auto subStream : subStreams) - csb->csb_rpt[subStream].activate(); + // Activate the priorly used rivers + for (const auto river : rivers) + river->activate(csb); bool sortCanBeUsed = true; SortNode* const orgSortNode = sort; @@ -904,7 +915,10 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack) // Outer joins are processed their own way if (!isInnerJoin()) + { + rivers.join(dependentRivers); rsb = generateOuterJoin(rivers, &sort); + } else { // AB: If previous rsb's are already on the stack we can't use @@ -971,13 +985,18 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack) } } - // attempt to form joins in decreasing order of desirability + // Attempt to form joins in decreasing order of desirability generateInnerJoin(joinStreams, rivers, &sort, rse->rse_plan); + // Re-activate remaining rivers to be hashable/mergeable + for (const auto river : rivers) + river->activate(csb); + // If there are multiple rivers, try some hashing or sort/merging while (generateEquiJoin(rivers)) ; + rivers.join(dependentRivers); rsb = CrossJoin(csb, rivers).getRecordSource(); // Pick up any residual boolean that may have fallen thru the cracks @@ -2263,6 +2282,9 @@ bool Optimizer::generateEquiJoin(RiverList& orgRivers) if (iter & CONJUNCT_USED) continue; + if (!iter->computable(csb, INVALID_STREAM, false)) + continue; + NestConst node1; NestConst node2; diff --git a/src/jrd/optimizer/Optimizer.h b/src/jrd/optimizer/Optimizer.h index ef9baa0f1a..3cc9b1de51 100644 --- a/src/jrd/optimizer/Optimizer.h +++ b/src/jrd/optimizer/Optimizer.h @@ -548,7 +548,7 @@ private: unsigned baseParentConjuncts = 0; // number of conjuncts in our rse + distributed with parent, next are parent unsigned baseMissingConjuncts = 0; // number of conjuncts in our and parent rse, but without missing - StreamList compileStreams, bedStreams, keyStreams, subStreams, outerStreams; + StreamList compileStreams, bedStreams, keyStreams, outerStreams; ConjunctList conjuncts; };