@@ -33,7 +33,7 @@ namespace NYql::NDq {
33
33
* This class is templated by std::bitset with the largest number of joins we can process
34
34
* or std::bitset<64>, which has a more efficient implementation of enumerating subsets of set.
35
35
*/
36
- template <typename TNodeSet>
36
+ template <typename TNodeSet, bool ProcessCycles >
37
37
class TDPHypSolver {
38
38
public:
39
39
TDPHypSolver (
@@ -58,7 +58,7 @@ class TDPHypSolver {
58
58
59
59
void EnumerateCmpRec (const TNodeSet& s1, const TNodeSet& s2, const TNodeSet& x);
60
60
61
- void EmitCsgCmp (const TNodeSet& s1, const TNodeSet& s2, const typename TJoinHypergraph<TNodeSet>::TEdge* csgCmpEdge);
61
+ void EmitCsgCmp (const TNodeSet& s1, const TNodeSet& s2, const typename TJoinHypergraph<TNodeSet>::TEdge* csgCmpEdge, const typename TJoinHypergraph<TNodeSet>::TEdge* reversedCsgCmpEdge );
62
62
63
63
private:
64
64
// Create an exclusion set that contains all the nodes of the graph that are smaller or equal to
@@ -113,7 +113,7 @@ class TDPHypSolver {
113
113
/*
114
114
* Count the number of items in the DP table of DPHyp
115
115
*/
116
- template <typename TNodeSet> ui32 TDPHypSolver<TNodeSet>::CountCC(ui32 budget) {
116
+ template <typename TNodeSet, bool ProcessCycles > ui32 TDPHypSolver<TNodeSet, ProcessCycles >::CountCC(ui32 budget) {
117
117
TNodeSet allNodes;
118
118
allNodes.set ();
119
119
ui32 cost = 0 ;
@@ -135,7 +135,7 @@ template <typename TNodeSet> ui32 TDPHypSolver<TNodeSet>::CountCC(ui32 budget) {
135
135
/* *
136
136
* Recursively count the nuber of items in the DP table of DPccp
137
137
*/
138
- template <typename TNodeSet> ui32 TDPHypSolver<TNodeSet>::CountCCRec(const TNodeSet& s, const TNodeSet& x, ui32 cost, ui32 budget) {
138
+ template <typename TNodeSet, bool ProcessCycles > ui32 TDPHypSolver<TNodeSet, ProcessCycles >::CountCCRec(const TNodeSet& s, const TNodeSet& x, ui32 cost, ui32 budget) {
139
139
TNodeSet neighs = Neighs (s, x);
140
140
141
141
if (neighs == TNodeSet{}) {
@@ -161,7 +161,7 @@ template <typename TNodeSet> ui32 TDPHypSolver<TNodeSet>::CountCCRec(const TNode
161
161
return cost;
162
162
}
163
163
164
- template <typename TNodeSet> TNodeSet TDPHypSolver<TNodeSet>::Neighs(TNodeSet s, TNodeSet x) {
164
+ template <typename TNodeSet, bool ProcessCycles > TNodeSet TDPHypSolver<TNodeSet, ProcessCycles >::Neighs(TNodeSet s, TNodeSet x) {
165
165
TNodeSet neighs{};
166
166
167
167
auto & nodes = Graph_.GetNodes ();
@@ -190,11 +190,16 @@ template<typename TNodeSet> TNodeSet TDPHypSolver<TNodeSet>::Neighs(TNodeSet s,
190
190
}
191
191
192
192
template <>
193
- inline std::bitset<64 > TDPHypSolver<std::bitset<64 >>::NextBitset(const std::bitset<64 >& prev, const std::bitset<64 >& final ) {
193
+ inline std::bitset<64 > TDPHypSolver<std::bitset<64 >, false >::NextBitset(const std::bitset<64 >& prev, const std::bitset<64 >& final ) {
194
194
return std::bitset<64 >((prev | ~final ).to_ulong () + 1 ) & final ;
195
195
}
196
196
197
- template <typename TNodeSet> TNodeSet TDPHypSolver<TNodeSet>::NextBitset(const TNodeSet& prev, const TNodeSet& final ) {
197
+ template <>
198
+ inline std::bitset<64 > TDPHypSolver<std::bitset<64 >, true >::NextBitset(const std::bitset<64 >& prev, const std::bitset<64 >& final ) {
199
+ return std::bitset<64 >((prev | ~final ).to_ulong () + 1 ) & final ;
200
+ }
201
+
202
+ template <typename TNodeSet, bool ProcessCycles> TNodeSet TDPHypSolver<TNodeSet, ProcessCycles>::NextBitset(const TNodeSet& prev, const TNodeSet& final ) {
198
203
if (prev == final ) {
199
204
return final ;
200
205
}
@@ -223,7 +228,7 @@ template<typename TNodeSet> TNodeSet TDPHypSolver<TNodeSet>::NextBitset(const TN
223
228
return res;
224
229
}
225
230
226
- template <typename TNodeSet> std::shared_ptr<TJoinOptimizerNodeInternal> TDPHypSolver<TNodeSet>::Solve(const TOptimizerHints& hints) {
231
+ template <typename TNodeSet, bool ProcessCycles > std::shared_ptr<TJoinOptimizerNodeInternal> TDPHypSolver<TNodeSet, ProcessCycles >::Solve(const TOptimizerHints& hints) {
227
232
for (auto & h : hints.CardinalityHints ->Hints ) {
228
233
TNodeSet hintSet = Graph_.GetNodesByRelNames (h.JoinLabels );
229
234
CardHintsTable_[hintSet] = &h;
@@ -270,7 +275,7 @@ template<typename TNodeSet> std::shared_ptr<TJoinOptimizerNodeInternal> TDPHypSo
270
275
* First it emits CSGs that are created by adding neighbors of S to S
271
276
* Then it recurses on the S fused with its neighbors.
272
277
*/
273
- template <typename TNodeSet> void TDPHypSolver<TNodeSet>::EnumerateCsgRec(const TNodeSet& s1, const TNodeSet& x) {
278
+ template <typename TNodeSet, bool ProcessCycles > void TDPHypSolver<TNodeSet, ProcessCycles >::EnumerateCsgRec(const TNodeSet& s1, const TNodeSet& x) {
274
279
TNodeSet neighs = Neighs (s1, x);
275
280
276
281
if (neighs == TNodeSet{}) {
@@ -313,7 +318,7 @@ template <typename TNodeSet> void TDPHypSolver<TNodeSet>::EnumerateCsgRec(const
313
318
* First it iterates through neighbors of the initial set S and emits pairs
314
319
* (S,S2), where S2 is the neighbor of S. Then it recursively emits complement pairs
315
320
*/
316
- template <typename TNodeSet> void TDPHypSolver<TNodeSet>::EmitCsg(const TNodeSet& s1) {
321
+ template <typename TNodeSet, bool ProcessCycles > void TDPHypSolver<TNodeSet, ProcessCycles >::EmitCsg(const TNodeSet& s1) {
317
322
TNodeSet x = s1 | MakeBiMin (s1);
318
323
TNodeSet neighs = Neighs (s1, x);
319
324
@@ -326,8 +331,15 @@ template <typename TNodeSet> void TDPHypSolver<TNodeSet>::EmitCsg(const TNodeSet
326
331
TNodeSet s2{};
327
332
s2[i] = 1 ;
328
333
329
- if (auto * edge = Graph_.FindEdgeBetween (s1, s2)) {
330
- EmitCsgCmp (s1, s2, edge);
334
+ if constexpr (ProcessCycles) {
335
+ if (auto edge = Graph_.FindEdgeWithAllConditionsBetween (s1, s2)) {
336
+ auto reversedEdge = edge->CreateReversed (-1 );
337
+ EmitCsgCmp (s1, s2, &edge.value (), &reversedEdge);
338
+ }
339
+ } else {
340
+ if (auto * edge = Graph_.FindEdgeBetween (s1, s2)) {
341
+ EmitCsgCmp (s1, s2, edge, &Graph_.GetEdge (edge->ReversedEdgeId ));
342
+ }
331
343
}
332
344
333
345
EnumerateCmpRec (s1, s2, x | MakeB (neighs, GetLowestSetBit (s2)));
@@ -341,7 +353,7 @@ template <typename TNodeSet> void TDPHypSolver<TNodeSet>::EmitCsg(const TNodeSet
341
353
* that are obtained by adding S2's neighbors to itself
342
354
* Then it recusrses into pairs (S1,S2+next)
343
355
*/
344
- template <typename TNodeSet> void TDPHypSolver<TNodeSet>::EnumerateCmpRec(const TNodeSet& s1, const TNodeSet& s2, const TNodeSet& x) {
356
+ template <typename TNodeSet, bool ProcessCycles > void TDPHypSolver<TNodeSet, ProcessCycles >::EnumerateCmpRec(const TNodeSet& s1, const TNodeSet& s2, const TNodeSet& x) {
345
357
TNodeSet neighs = Neighs (s2, x);
346
358
347
359
if (neighs == TNodeSet{}) {
@@ -355,8 +367,15 @@ template <typename TNodeSet> void TDPHypSolver<TNodeSet>::EnumerateCmpRec(const
355
367
next = NextBitset (prev, neighs);
356
368
357
369
if (DpTable_.contains (s2 | next)) {
358
- if (auto * edge = Graph_.FindEdgeBetween (s1, s2 | next)) {
359
- EmitCsgCmp (s1, s2 | next, edge);
370
+ if constexpr (ProcessCycles) {
371
+ if (auto edge = Graph_.FindEdgeWithAllConditionsBetween (s1, s2 | next)) {
372
+ auto reversedEdge = edge->CreateReversed (-1 );
373
+ EmitCsgCmp (s1, s2 | next, &edge.value (), &reversedEdge);
374
+ }
375
+ } else {
376
+ if (auto * edge = Graph_.FindEdgeBetween (s1, s2 | next)) {
377
+ EmitCsgCmp (s1, s2 | next, edge, &Graph_.GetEdge (edge->ReversedEdgeId ));
378
+ }
360
379
}
361
380
}
362
381
@@ -381,7 +400,7 @@ template <typename TNodeSet> void TDPHypSolver<TNodeSet>::EnumerateCmpRec(const
381
400
}
382
401
}
383
402
384
- template <typename TNodeSet> TNodeSet TDPHypSolver<TNodeSet>::MakeBiMin(const TNodeSet& s) {
403
+ template <typename TNodeSet, bool ProcessCycles > TNodeSet TDPHypSolver<TNodeSet, ProcessCycles >::MakeBiMin(const TNodeSet& s) {
385
404
TNodeSet res{};
386
405
387
406
for (size_t i = 0 ; i < NNodes_; i++) {
@@ -395,7 +414,7 @@ template <typename TNodeSet> TNodeSet TDPHypSolver<TNodeSet>::MakeBiMin(const TN
395
414
return res;
396
415
}
397
416
398
- template <typename TNodeSet> TNodeSet TDPHypSolver<TNodeSet>::MakeB(const TNodeSet& s, size_t v) {
417
+ template <typename TNodeSet, bool ProcessCycles > TNodeSet TDPHypSolver<TNodeSet, ProcessCycles >::MakeB(const TNodeSet& s, size_t v) {
399
418
TNodeSet res{};
400
419
401
420
for (size_t i = 0 ; i < NNodes_; i++) {
@@ -407,7 +426,7 @@ template <typename TNodeSet> TNodeSet TDPHypSolver<TNodeSet>::MakeB(const TNodeS
407
426
return res;
408
427
}
409
428
410
- template <typename TNodeSet> std::shared_ptr<TJoinOptimizerNodeInternal> TDPHypSolver<TNodeSet>::PickBestJoin(
429
+ template <typename TNodeSet, bool ProcessCycles > std::shared_ptr<TJoinOptimizerNodeInternal> TDPHypSolver<TNodeSet, ProcessCycles >::PickBestJoin(
411
430
const std::shared_ptr<IBaseOptimizerNode>& left,
412
431
const std::shared_ptr<IBaseOptimizerNode>& right,
413
432
EJoinKind joinKind,
@@ -434,7 +453,7 @@ template <typename TNodeSet> std::shared_ptr<TJoinOptimizerNodeInternal> TDPHypS
434
453
for (auto joinAlgo : AllJoinAlgos) {
435
454
if (ctx.IsJoinApplicable (left, right, joinConditions, leftJoinKeys, rightJoinKeys, joinAlgo, joinKind)){
436
455
auto cost = ctx.ComputeJoinStats (*left->Stats , *right->Stats , leftJoinKeys, rightJoinKeys, joinAlgo, joinKind, maybeCardHint).Cost ;
437
- if (cost < bestCost) {
456
+ if (cost <= bestCost) {
438
457
bestCost = cost;
439
458
bestAlgo = joinAlgo;
440
459
bestJoinIsReversed = false ;
@@ -444,7 +463,7 @@ template <typename TNodeSet> std::shared_ptr<TJoinOptimizerNodeInternal> TDPHypS
444
463
if (isCommutative) {
445
464
if (ctx.IsJoinApplicable (right, left, reversedJoinConditions, rightJoinKeys, leftJoinKeys, joinAlgo, joinKind)){
446
465
auto cost = ctx.ComputeJoinStats (*right->Stats , *left->Stats , rightJoinKeys, leftJoinKeys, joinAlgo, joinKind, maybeCardHint).Cost ;
447
- if (cost < bestCost) {
466
+ if (cost <= bestCost) {
448
467
bestCost = cost;
449
468
bestAlgo = joinAlgo;
450
469
bestJoinIsReversed = true ;
@@ -465,19 +484,23 @@ template <typename TNodeSet> std::shared_ptr<TJoinOptimizerNodeInternal> TDPHypS
465
484
/*
466
485
* Emit a single CSG + CMP pair
467
486
*/
468
- template <typename TNodeSet> void TDPHypSolver<TNodeSet>::EmitCsgCmp(const TNodeSet& s1, const TNodeSet& s2, const typename TJoinHypergraph<TNodeSet>::TEdge* csgCmpEdge) {
487
+ template <typename TNodeSet, bool ProcessCycles> void TDPHypSolver<TNodeSet, ProcessCycles>::EmitCsgCmp(
488
+ const TNodeSet& s1,
489
+ const TNodeSet& s2,
490
+ const typename TJoinHypergraph<TNodeSet>::TEdge* csgCmpEdge,
491
+ const typename TJoinHypergraph<TNodeSet>::TEdge* reversedCsgCmpEdge
492
+ ) {
469
493
// Here we actually build the join and choose and compare the
470
494
// new plan to what's in the dpTable, if it there
471
495
472
496
Y_ENSURE (DpTable_.contains (s1), " DP Table does not contain S1" );
473
497
Y_ENSURE (DpTable_.contains (s2), " DP Table does not conaint S2" );
474
498
475
- const auto * reversedEdge = &Graph_.GetEdge (csgCmpEdge->ReversedEdgeId );
476
499
auto leftNodes = DpTable_[s1];
477
500
auto rightNodes = DpTable_[s2];
478
501
479
502
if (csgCmpEdge->IsReversed ) {
480
- std::swap (csgCmpEdge, reversedEdge );
503
+ std::swap (csgCmpEdge, reversedCsgCmpEdge );
481
504
std::swap (leftNodes, rightNodes);
482
505
}
483
506
@@ -494,7 +517,7 @@ template<typename TNodeSet> void TDPHypSolver<TNodeSet>::EmitCsgCmp(const TNodeS
494
517
csgCmpEdge->RightAny ,
495
518
csgCmpEdge->IsCommutative ,
496
519
csgCmpEdge->JoinConditions ,
497
- reversedEdge ->JoinConditions ,
520
+ reversedCsgCmpEdge ->JoinConditions ,
498
521
csgCmpEdge->LeftJoinKeys ,
499
522
csgCmpEdge->RightJoinKeys ,
500
523
Pctx_,
@@ -509,7 +532,7 @@ template<typename TNodeSet> void TDPHypSolver<TNodeSet>::EmitCsgCmp(const TNodeS
509
532
#ifndef NDEBUG
510
533
auto pair = std::make_pair (s1, s2);
511
534
Y_ENSURE (!CheckTable_.contains (pair), " Check table already contains pair S1|S2" );
512
- CheckTable_[ std:: pair<TNodeSet,TNodeSet>(s1, s2) ] = true ;
535
+ CheckTable_[pair] = true ;
513
536
#endif
514
537
}
515
538
0 commit comments