@@ -19,23 +19,6 @@ function safeMax(it?: Iterable<number>) {
19
19
return Number . isFinite ( m ) ? m : 0 ;
20
20
}
21
21
22
- /**
23
- * Compute a key for the maps that that is sent to report generation.
24
- * Should only be used on events that are known to define queryCausingWork.
25
- */
26
- function makeKey (
27
- queryCausingWork : string | undefined ,
28
- predicate : string ,
29
- suffix = "" ,
30
- ) : string {
31
- if ( queryCausingWork === undefined ) {
32
- throw new Error (
33
- "queryCausingWork was not defined on an event we expected it to be defined for!" ,
34
- ) ;
35
- }
36
- return `${ queryCausingWork } :${ predicate } ${ suffix ? ` ${ suffix } ` : "" } ` ;
37
- }
38
-
39
22
function getDependentPredicates ( operations : string [ ] ) : string [ ] {
40
23
const id = String . raw `[0-9a-zA-Z:#_\./]+` ;
41
24
const idWithAngleBrackets = String . raw `[0-9a-zA-Z:#_<>\./]+` ;
@@ -128,14 +111,6 @@ function pointwiseSum(
128
111
return result ;
129
112
}
130
113
131
- function pushValue < K , V > ( m : Map < K , V [ ] > , k : K , v : V ) {
132
- if ( ! m . has ( k ) ) {
133
- m . set ( k , [ ] ) ;
134
- }
135
- m . get ( k ) ! . push ( v ) ;
136
- return m ;
137
- }
138
-
139
114
function computeJoinOrderBadness (
140
115
maxTupleCount : number ,
141
116
maxDependentPredicateSize : number ,
@@ -161,11 +136,6 @@ class JoinOrderScanner implements EvaluationLogScanner {
161
136
string ,
162
137
Array < ComputeRecursive | InLayer >
163
138
> ( ) ;
164
- // Map a key of the form 'query-with-demand : predicate name' to its badness input.
165
- private readonly maxTupleCountMap = new Map < string , number [ ] > ( ) ;
166
- private readonly resultSizeMap = new Map < string , number [ ] > ( ) ;
167
- private readonly maxDependentPredicateSizeMap = new Map < string , number [ ] > ( ) ;
168
- private readonly joinOrderMetricMap = new Map < string , number > ( ) ;
169
139
170
140
constructor (
171
141
private readonly problemReporter : EvaluationLogProblemReporter ,
@@ -216,27 +186,6 @@ class JoinOrderScanner implements EvaluationLogScanner {
216
186
}
217
187
}
218
188
219
- private reportProblemIfNecessary (
220
- event : SummaryEvent ,
221
- iteration : number ,
222
- metric : number ,
223
- ) : void {
224
- if ( metric >= this . warningThreshold ) {
225
- this . problemReporter . reportProblem (
226
- event . predicateName ,
227
- event . raHash ,
228
- iteration ,
229
- `Relation '${
230
- event . predicateName
231
- } ' has an inefficient join order. Its join order metric is ${ metric . toFixed (
232
- 2 ,
233
- ) } , which is larger than the threshold of ${ this . warningThreshold . toFixed (
234
- 2 ,
235
- ) } .`,
236
- ) ;
237
- }
238
- }
239
-
240
189
private computeBadnessMetric ( event : SummaryEvent ) : void {
241
190
if (
242
191
event . completionType !== undefined &&
@@ -252,28 +201,32 @@ class JoinOrderScanner implements EvaluationLogScanner {
252
201
}
253
202
// Compute the badness metric for a non-recursive predicate. The metric in this case is defined as:
254
203
// badness = (max tuple count in the pipeline) / (largest predicate this pipeline depends on)
255
- const key = makeKey ( event . queryCausingWork , event . predicateName ) ;
256
204
const resultSize = event . resultSize ;
257
205
258
206
// There is only one entry in `pipelineRuns` if it's a non-recursive predicate.
259
207
const { maxTupleCount, maxDependentPredicateSize } =
260
208
this . badnessInputsForNonRecursiveDelta ( event . pipelineRuns [ 0 ] , event ) ;
261
209
262
210
if ( maxDependentPredicateSize > 0 ) {
263
- pushValue ( this . maxTupleCountMap , key , maxTupleCount ) ;
264
- pushValue ( this . resultSizeMap , key , resultSize ) ;
265
- pushValue (
266
- this . maxDependentPredicateSizeMap ,
267
- key ,
268
- maxDependentPredicateSize ,
269
- ) ;
270
211
const metric = computeJoinOrderBadness (
271
212
maxTupleCount ,
272
213
maxDependentPredicateSize ,
273
214
resultSize ! ,
274
215
) ;
275
- this . joinOrderMetricMap . set ( key , metric ) ;
276
- this . reportProblemIfNecessary ( event , 0 , metric ) ;
216
+ if ( metric >= this . warningThreshold ) {
217
+ const message = `'${
218
+ event . predicateName
219
+ } ' has an inefficient join order. Its join order metric is ${ metric . toFixed (
220
+ 2 ,
221
+ ) } , which is larger than the threshold of ${ this . warningThreshold . toFixed (
222
+ 2 ,
223
+ ) } .`;
224
+ this . problemReporter . reportProblemNonRecursive (
225
+ event . predicateName ,
226
+ event . raHash ,
227
+ message ,
228
+ ) ;
229
+ }
277
230
}
278
231
break ;
279
232
}
@@ -282,39 +235,39 @@ class JoinOrderScanner implements EvaluationLogScanner {
282
235
// Compute the badness metric for a recursive predicate for each ordering.
283
236
const sccMetricInput = this . badnessInputsForRecursiveDelta ( event ) ;
284
237
// Loop through each predicate in the SCC
285
- sccMetricInput . forEach ( ( buckets , predicate ) => {
286
- // Loop through each ordering of the predicate
287
- buckets . forEach ( ( bucket , raReference ) => {
288
- // Format the key as demanding-query:name (ordering)
289
- const key = makeKey (
290
- event . queryCausingWork ,
291
- predicate ,
292
- `(${ raReference } )` ,
293
- ) ;
294
- const maxTupleCount = Math . max ( ...bucket . tupleCounts ) ;
295
- const resultSize = bucket . resultSize ;
296
- const maxDependentPredicateSize = Math . max (
297
- ...bucket . dependentPredicateSizes . values ( ) ,
298
- ) ;
299
-
300
- if ( maxDependentPredicateSize > 0 ) {
301
- pushValue ( this . maxTupleCountMap , key , maxTupleCount ) ;
302
- pushValue ( this . resultSizeMap , key , resultSize ) ;
303
- pushValue (
304
- this . maxDependentPredicateSizeMap ,
305
- key ,
306
- maxDependentPredicateSize ,
238
+ sccMetricInput . forEach ( ( hashToOrderToBucket , predicateName ) => {
239
+ hashToOrderToBucket . forEach ( ( orderToBucket , raHash ) => {
240
+ // Loop through each ordering of the predicate.
241
+ orderToBucket . forEach ( ( bucket , raReference ) => {
242
+ const maxDependentPredicateSize = Math . max (
243
+ ...bucket . dependentPredicateSizes . values ( ) ,
307
244
) ;
308
- const metric = computeJoinOrderBadness (
309
- maxTupleCount ,
310
- maxDependentPredicateSize ,
311
- resultSize ,
312
- ) ;
313
- const oldMetric = this . joinOrderMetricMap . get ( key ) ;
314
- if ( oldMetric === undefined || metric > oldMetric ) {
315
- this . joinOrderMetricMap . set ( key , metric ) ;
245
+
246
+ if ( maxDependentPredicateSize > 0 ) {
247
+ const maxTupleCount = Math . max ( ...bucket . tupleCounts ) ;
248
+ const resultSize = bucket . resultSize ;
249
+ const metric = computeJoinOrderBadness (
250
+ maxTupleCount ,
251
+ maxDependentPredicateSize ,
252
+ resultSize ,
253
+ ) ;
254
+ if ( metric >= this . warningThreshold ) {
255
+ const message = `The ${ raReference } pipeline for '${
256
+ predicateName
257
+ } ' has an inefficient join order. Its join order metric is ${ metric . toFixed (
258
+ 2 ,
259
+ ) } , which is larger than the threshold of ${ this . warningThreshold . toFixed (
260
+ 2 ,
261
+ ) } .`;
262
+ this . problemReporter . reportProblemForRecursionSummary (
263
+ predicateName ,
264
+ raHash ,
265
+ raReference ,
266
+ message ,
267
+ ) ;
268
+ }
316
269
}
317
- }
270
+ } ) ;
318
271
} ) ;
319
272
} ) ;
320
273
break ;
@@ -457,20 +410,28 @@ class JoinOrderScanner implements EvaluationLogScanner {
457
410
*/
458
411
private badnessInputsForRecursiveDelta (
459
412
event : ComputeRecursive ,
460
- ) : Map < string , Map < string , Bucket > > {
461
- // nameToOrderToBucket : predicate name -> ordering (i.e., standard, order_500000, etc.) -> bucket
462
- const nameToOrderToBucket = new Map < string , Map < string , Bucket > > ( ) ;
413
+ ) : Map < string , Map < string , Map < string , Bucket > > > {
414
+ // nameToHashToOrderToBucket : predicate name -> RA hash -> ordering (i.e., standard, order_500000, etc.) -> bucket
415
+ const nameToHashToOrderToBucket = new Map <
416
+ string ,
417
+ Map < string , Map < string , Bucket > >
418
+ > ( ) ;
463
419
464
420
// Iterate through the SCC and compute the metric inputs
465
421
this . iterateSCC ( event , ( inLayerEvent , run , iteration ) => {
466
422
const raReference = run . raReference ;
467
423
const predicateName = inLayerEvent . predicateName ;
468
- if ( ! nameToOrderToBucket . has ( predicateName ) ) {
469
- nameToOrderToBucket . set ( predicateName , new Map ( ) ) ;
424
+ if ( ! nameToHashToOrderToBucket . has ( predicateName ) ) {
425
+ nameToHashToOrderToBucket . set ( predicateName , new Map ( ) ) ;
426
+ }
427
+ const hashToOrderToBucket = nameToHashToOrderToBucket . get ( predicateName ) ! ;
428
+ const raHash = inLayerEvent . raHash ;
429
+ if ( ! hashToOrderToBucket . has ( raHash ) ) {
430
+ hashToOrderToBucket . set ( raHash , new Map ( ) ) ;
470
431
}
471
- const orderTobucket = nameToOrderToBucket . get ( predicateName ) ! ;
472
- if ( ! orderTobucket . has ( raReference ) ) {
473
- orderTobucket . set ( raReference , {
432
+ const orderToBucket = hashToOrderToBucket . get ( raHash ) ! ;
433
+ if ( ! orderToBucket . has ( raReference ) ) {
434
+ orderToBucket . set ( raReference , {
474
435
tupleCounts : new Int32Array ( 0 ) ,
475
436
resultSize : 0 ,
476
437
dependentPredicateSizes : new Map ( ) ,
@@ -484,7 +445,7 @@ class JoinOrderScanner implements EvaluationLogScanner {
484
445
iteration ,
485
446
) ;
486
447
487
- const bucket = orderTobucket . get ( raReference ) ! ;
448
+ const bucket = orderToBucket . get ( raReference ) ! ;
488
449
// Pointwise sum the tuple counts
489
450
const newTupleCounts = pointwiseSum (
490
451
bucket . tupleCounts ,
@@ -504,13 +465,13 @@ class JoinOrderScanner implements EvaluationLogScanner {
504
465
) ;
505
466
}
506
467
507
- orderTobucket . set ( raReference , {
468
+ orderToBucket . set ( raReference , {
508
469
tupleCounts : newTupleCounts ,
509
470
resultSize,
510
471
dependentPredicateSizes : newDependentPredicateSizes ,
511
472
} ) ;
512
473
} ) ;
513
- return nameToOrderToBucket ;
474
+ return nameToHashToOrderToBucket ;
514
475
}
515
476
}
516
477
0 commit comments