@@ -116,44 +116,67 @@ TExprBase BuildDqJoinInput(TExprContext& ctx, TPositionHandle pos, const TExprBa
116116 return partition;
117117}
118118
119- TMaybe<TJoinInputDesc> BuildDqJoin (const TCoEquiJoinTuple& joinTuple,
120- const THashMap<TStringBuf, TJoinInputDesc>& inputs, EHashJoinMode mode, bool useCBO, TExprContext& ctx, const TTypeAnnotationContext& typeCtx)
119+ TMaybe<TJoinInputDesc> BuildDqJoin (
120+ const TCoEquiJoinTuple& joinTuple,
121+ const THashMap<TStringBuf, TJoinInputDesc>& inputs,
122+ EHashJoinMode mode,
123+ TExprContext& ctx,
124+ const TTypeAnnotationContext& typeCtx,
125+ TVector<TString>& subtreeLabels,
126+ const NYql::TOptimizerHints& hints
127+ )
121128{
122- auto options = joinTuple.Options ();
123- auto linkSettings = GetEquiJoinLinkSettings (options.Ref ());
124- YQL_ENSURE (linkSettings.JoinAlgo != EJoinAlgoType::StreamLookupJoin || typeCtx.StreamLookupJoin , " Unsupported join strategy: streamlookup" );
125-
126- if (linkSettings.JoinAlgo == EJoinAlgoType::MapJoin) {
127- mode = EHashJoinMode::Map;
128- } else if (linkSettings.JoinAlgo == EJoinAlgoType::GraceJoin) {
129- mode = EHashJoinMode::GraceAndSelf;
130- }
131-
132- bool leftAny = linkSettings.LeftHints .contains (" any" );
133- bool rightAny = linkSettings.RightHints .contains (" any" );
134-
135129 TMaybe<TJoinInputDesc> left;
130+ TVector<TString> lhsLabels;
136131 if (joinTuple.LeftScope ().Maybe <TCoAtom>()) {
132+ lhsLabels.push_back (joinTuple.LeftScope ().Cast <TCoAtom>().StringValue ());
137133 left = inputs.at (joinTuple.LeftScope ().Cast <TCoAtom>().Value ());
138134 YQL_ENSURE (left, " unknown scope " << joinTuple.LeftScope ().Cast <TCoAtom>().Value ());
139135 } else {
140- left = BuildDqJoin (joinTuple.LeftScope ().Cast <TCoEquiJoinTuple>(), inputs, mode, useCBO, ctx, typeCtx);
136+ left = BuildDqJoin (joinTuple.LeftScope ().Cast <TCoEquiJoinTuple>(), inputs, mode, ctx, typeCtx, lhsLabels, hints );
141137 if (!left) {
142138 return {};
143139 }
144140 }
145141
146142 TMaybe<TJoinInputDesc> right;
143+ TVector<TString> rhsLabels;
147144 if (joinTuple.RightScope ().Maybe <TCoAtom>()) {
145+ rhsLabels.push_back (joinTuple.RightScope ().Cast <TCoAtom>().StringValue ());
148146 right = inputs.at (joinTuple.RightScope ().Cast <TCoAtom>().Value ());
149147 YQL_ENSURE (right, " unknown scope " << joinTuple.RightScope ().Cast <TCoAtom>().Value ());
150148 } else {
151- right = BuildDqJoin (joinTuple.RightScope ().Cast <TCoEquiJoinTuple>(), inputs, mode, useCBO, ctx, typeCtx);
149+ right = BuildDqJoin (joinTuple.RightScope ().Cast <TCoEquiJoinTuple>(), inputs, mode, ctx, typeCtx, rhsLabels, hints );
152150 if (!right) {
153151 return {};
154152 }
155153 }
156154
155+ subtreeLabels.insert (subtreeLabels.end (), std::make_move_iterator (lhsLabels.begin ()), std::make_move_iterator (lhsLabels.end ()));
156+ subtreeLabels.insert (subtreeLabels.end (), std::make_move_iterator (rhsLabels.begin ()), std::make_move_iterator (rhsLabels.end ()));
157+
158+ auto options = joinTuple.Options ();
159+ auto linkSettings = GetEquiJoinLinkSettings (options.Ref ());
160+ for (auto & hint: hints.JoinAlgoHints ->Hints ) {
161+ if (
162+ std::unordered_set<std::string>(hint.JoinLabels .begin (), hint.JoinLabels .end ()) ==
163+ std::unordered_set<std::string>(subtreeLabels.begin (), subtreeLabels.end ())
164+ ) {
165+ linkSettings.JoinAlgo = hint.Algo ;
166+ hint.Applied = true ;
167+ }
168+ }
169+ YQL_ENSURE (linkSettings.JoinAlgo != EJoinAlgoType::StreamLookupJoin || typeCtx.StreamLookupJoin , " Unsupported join strategy: streamlookup" );
170+
171+ if (linkSettings.JoinAlgo == EJoinAlgoType::MapJoin) {
172+ mode = EHashJoinMode::Map;
173+ } else if (linkSettings.JoinAlgo == EJoinAlgoType::GraceJoin) {
174+ mode = EHashJoinMode::GraceAndSelf;
175+ }
176+
177+ bool leftAny = linkSettings.LeftHints .contains (" any" );
178+ bool rightAny = linkSettings.RightHints .contains (" any" );
179+
157180 TStringBuf joinType = joinTuple.Type ().Value ();
158181 TSet<std::pair<TStringBuf, TStringBuf>> resultKeys;
159182 if (joinType != TStringBuf (" RightOnly" ) && joinType != TStringBuf (" RightSemi" )) {
@@ -379,17 +402,32 @@ bool CheckJoinColumns(const TExprBase& node) {
379402 }
380403}
381404
382- TExprBase DqRewriteEquiJoin (const TExprBase& node, EHashJoinMode mode, bool useCBO, TExprContext& ctx, const TTypeAnnotationContext& typeCtx) {
383- int dummyJoinCounter;
384- return DqRewriteEquiJoin (node, mode, useCBO, ctx, typeCtx, dummyJoinCounter);
405+ TExprBase DqRewriteEquiJoin (
406+ const TExprBase& node,
407+ EHashJoinMode mode,
408+ bool useCBO,
409+ TExprContext& ctx,
410+ const TTypeAnnotationContext& typeCtx,
411+ const TOptimizerHints& hints
412+ ) {
413+ int dummyJoinCounter = 0 ;
414+ return DqRewriteEquiJoin (node, mode, useCBO, ctx, typeCtx, dummyJoinCounter, hints);
385415}
386416
387417/* *
388418 * Rewrite `EquiJoin` to a number of `DqJoin` callables. This is done to simplify next step of building
389419 * physical stages with join operators.
390420 * Potentially this optimizer can also perform joins reorder given cardinality information.
391421 */
392- TExprBase DqRewriteEquiJoin (const TExprBase& node, EHashJoinMode mode, bool useCBO, TExprContext& ctx, const TTypeAnnotationContext& typeCtx, int & joinCounter) {
422+ TExprBase DqRewriteEquiJoin (
423+ const TExprBase& node,
424+ EHashJoinMode mode,
425+ bool /* useCBO */ ,
426+ TExprContext& ctx,
427+ const TTypeAnnotationContext& typeCtx,
428+ int & joinCounter,
429+ const TOptimizerHints& hints
430+ ) {
393431 if (!node.Maybe <TCoEquiJoin>()) {
394432 return node;
395433 }
@@ -406,7 +444,8 @@ TExprBase DqRewriteEquiJoin(const TExprBase& node, EHashJoinMode mode, bool useC
406444 }
407445
408446 auto joinTuple = equiJoin.Arg (equiJoin.ArgCount () - 2 ).Cast <TCoEquiJoinTuple>();
409- auto result = BuildDqJoin (joinTuple, inputs, mode, useCBO, ctx, typeCtx);
447+ TVector<TString> dummy;
448+ auto result = BuildDqJoin (joinTuple, inputs, mode, ctx, typeCtx, dummy, hints);
410449 if (!result) {
411450 return node;
412451 }
0 commit comments