@@ -52,6 +52,7 @@ final class SketchJoinOrderPlanner {
5252 private static final double SMALL_BINDING_SET_ASSIGNMENT_SCORE_RATIO = 0.05d ;
5353 private static final double BOUND_TYPE_GUARD_DELAY_PENALTY = 4.0d ;
5454 private static final double PENDING_SMALL_VALUES_ANCHOR_FILTER_PENALTY = 4.0d ;
55+ private static final double PENDING_TYPE_GUARD_BROAD_SCAN_RATIO = 4.0d ;
5556 private static final double BROAD_EDGE_PENDING_CONSTRAINT_PENALTY = 4.0d ;
5657 private static final double MAX_BROAD_EDGE_PENDING_CONSTRAINT_PENALTY = 1024.0d ;
5758 private static final double BROAD_EDGE_MIN_ROWS = 1024.0d ;
@@ -1170,9 +1171,7 @@ private double adjustedWorkRows(SketchBasedJoinEstimator.AccessShape accessShape
11701171 if (!(Double .isFinite (adjustedWorkRows ) && adjustedWorkRows > 0.0d )) {
11711172 return defaultWorkRows ;
11721173 }
1173- return Double .isFinite (defaultWorkRows ) && defaultWorkRows >= 0.0d
1174- ? Math .min (adjustedWorkRows , defaultWorkRows )
1175- : adjustedWorkRows ;
1174+ return adjustedWorkRows ;
11761175 }
11771176
11781177 private double adjustedTransitionWorkRows (int factorIndex , long mask , long currentlyBoundVarMask ,
@@ -1210,20 +1209,13 @@ private double repeatedLookupWorkRows(SketchBasedJoinEstimator.TuplePlanEstimate
12101209 }
12111210
12121211 private double applyUnlockedFilterWorkRows (long previousMask , long nextMask , double workRows ) {
1213- double passRatio = newlyUnlockedFilterPassRatio (previousMask , nextMask );
1214- if (passRatio >= 1.0d ) {
1215- return workRows ;
1216- }
1217- double filteredWorkRows = workRows * passRatio ;
1218- if (!Double .isFinite (filteredWorkRows ) || filteredWorkRows < 0.0d ) {
1219- return workRows ;
1220- }
1221- return filteredWorkRows ;
1212+ return workRows ;
12221213 }
12231214
12241215 private double orderingScoreRows (int factorIndex , long previousMask , long nextMask , double workRows ,
12251216 double outputRows , double prefixRows ) {
1226- double scoreRows = workRows * newlyUnlockedFilterScoreRatio (previousMask , nextMask );
1217+ double unlockedFilterScoreRatio = newlyUnlockedFilterScoreRatio (previousMask , nextMask );
1218+ double scoreRows = workRows * unlockedFilterScoreRatio ;
12271219 if (!Double .isFinite (scoreRows ) || scoreRows < 0.0d ) {
12281220 scoreRows = workRows ;
12291221 }
@@ -1233,9 +1225,11 @@ private double orderingScoreRows(int factorIndex, long previousMask, long nextMa
12331225 scoreRows *= pendingConstraintPenalty ;
12341226 }
12351227 double localFilterMultiplier = selectiveLocalFilterMultiplier (factorIndex );
1228+ boolean hasSelectiveFilterScore = unlockedFilterScoreRatio < 1.0d ;
12361229 if (localFilterMultiplier < 1.0d && Double .isFinite (outputRows ) && outputRows >= 0.0d ) {
12371230 scoreRows = Math .min (scoreRows , outputRows );
12381231 scoreRows *= Math .max (localFilterMultiplier , CHEAP_UNLOCKED_FILTER_SCORE_RATIO );
1232+ hasSelectiveFilterScore = true ;
12391233 }
12401234 scoreRows *= pendingCheapFilterUnlockBeforeBroadEdgePenalty (previousMask , factorIndex );
12411235 if (hasSelectiveLocalFilter (factorIndex ) && hasPendingSmallValuesAnchoredSibling (previousMask , factorIndex )) {
@@ -1244,6 +1238,14 @@ private double orderingScoreRows(int factorIndex, long previousMask, long nextMa
12441238 if (hasSelectiveLocalFilter (factorIndex ) && hasValuesAnchoredStructuralBridge (previousMask , factorIndex )) {
12451239 scoreRows *= PENDING_SMALL_VALUES_ANCHOR_FILTER_PENALTY ;
12461240 }
1241+ if (previousMask == 0L && hasSelectiveFilterScore ) {
1242+ double typeGuardScoreRows = pendingSmallSameSubjectRdfTypeGuardScoreRows (factorIndex );
1243+ if (Double .isFinite (typeGuardScoreRows ) && typeGuardScoreRows >= 0.0d
1244+ && Double .isFinite (workRows )
1245+ && typeGuardScoreRows * PENDING_TYPE_GUARD_BROAD_SCAN_RATIO < workRows ) {
1246+ scoreRows = Math .max (scoreRows , Math .nextUp (typeGuardScoreRows ));
1247+ }
1248+ }
12471249 double reachableSelectiveFilterRatio = newlyReachableSelectiveLocalFilterRatio (previousMask , nextMask );
12481250 if (reachableSelectiveFilterRatio < 1.0d ) {
12491251 scoreRows *= reachableSelectiveFilterRatio ;
@@ -1263,6 +1265,55 @@ private double orderingScoreRows(int factorIndex, long previousMask, long nextMa
12631265 return scoreRows ;
12641266 }
12651267
1268+ private double pendingSmallSameSubjectRdfTypeGuardScoreRows (int factorIndex ) {
1269+ StatementPattern statementPattern = statementPattern (factors .get (factorIndex ).tupleExpr ());
1270+ if (statementPattern == null || hasConstantValue (statementPattern .getPredicateVar (), RDF_TYPE_IRI )) {
1271+ return Double .NaN ;
1272+ }
1273+ Var subjectVar = statementPattern .getSubjectVar ();
1274+ if (subjectVar == null || subjectVar .hasValue () || subjectVar .getName () == null ) {
1275+ return Double .NaN ;
1276+ }
1277+
1278+ String subjectName = subjectVar .getName ();
1279+ double bestScoreRows = Double .POSITIVE_INFINITY ;
1280+ for (int i = 0 ; i < factors .size (); i ++) {
1281+ if (i == factorIndex ) {
1282+ continue ;
1283+ }
1284+ double scoreRows = smallSameSubjectRdfTypeGuardScoreRows (i , subjectName );
1285+ if (Double .isFinite (scoreRows ) && scoreRows >= 0.0d && scoreRows < bestScoreRows ) {
1286+ bestScoreRows = scoreRows ;
1287+ }
1288+ }
1289+ return bestScoreRows < Double .POSITIVE_INFINITY ? bestScoreRows : Double .NaN ;
1290+ }
1291+
1292+ private double smallSameSubjectRdfTypeGuardScoreRows (int factorIndex , String subjectName ) {
1293+ PlanFactor factor = factors .get (factorIndex );
1294+ StatementPattern statementPattern = statementPattern (factor .tupleExpr ());
1295+ if (statementPattern == null || !hasConstantValue (statementPattern .getPredicateVar (), RDF_TYPE_IRI )) {
1296+ return Double .NaN ;
1297+ }
1298+ Var subjectVar = statementPattern .getSubjectVar ();
1299+ if (subjectVar == null || subjectVar .hasValue () || !subjectName .equals (subjectVar .getName ())
1300+ || statementPattern .getObjectVar () == null || !statementPattern .getObjectVar ().hasValue ()) {
1301+ return Double .NaN ;
1302+ }
1303+ if (!hasOnlySubjectPlannerJoinVar (factor , subjectName )) {
1304+ return Double .NaN ;
1305+ }
1306+ double outputRows = factor .estimate ().outputRows ();
1307+ if (!(Double .isFinite (outputRows ) && outputRows >= 0.0d && outputRows <= BROAD_EDGE_MIN_ROWS )) {
1308+ return Double .NaN ;
1309+ }
1310+ double adjustedWorkRows = adjustedWorkRows (factorIndex , 0L , initiallyBoundVarMask , outputRows );
1311+ if (!Double .isFinite (adjustedWorkRows ) || adjustedWorkRows < 0.0d ) {
1312+ return outputRows ;
1313+ }
1314+ return Math .max (outputRows , adjustedWorkRows );
1315+ }
1316+
12661317 private double boundTypeGuardDelayPenalty (long previousMask , int factorIndex ) {
12671318 if (previousMask == 0L || contains (previousMask , factorIndex )
12681319 || !maskHasSelectiveLocalFilter (previousMask )
@@ -1284,19 +1335,31 @@ private double boundTypeGuardDelayPenalty(long previousMask, int factorIndex) {
12841335
12851336 private boolean isBoundRdfTypeGuard (long previousMask , int factorIndex ) {
12861337 PlanFactor factor = factors .get (factorIndex );
1287- if (factor .joinVars ().size () != 1 ) {
1288- return false ;
1289- }
12901338 StatementPattern statementPattern = statementPattern (factor .tupleExpr ());
12911339 if (statementPattern == null || !hasConstantValue (statementPattern .getPredicateVar (), RDF_TYPE_IRI )) {
12921340 return false ;
12931341 }
12941342 Var subjectVar = statementPattern .getSubjectVar ();
12951343 return subjectVar != null && subjectVar .getName () != null
1344+ && hasOnlySubjectPlannerJoinVar (factor , subjectVar .getName ())
12961345 && containsVariable (variablesMask (previousMask ), subjectVar .getName ())
12971346 && statementPattern .getObjectVar () != null && statementPattern .getObjectVar ().hasValue ();
12981347 }
12991348
1349+ private static boolean hasOnlySubjectPlannerJoinVar (PlanFactor factor , String subjectName ) {
1350+ boolean hasSubject = false ;
1351+ for (String joinVar : factor .joinVars ()) {
1352+ if (!isPlannerVariableName (joinVar )) {
1353+ continue ;
1354+ }
1355+ if (!subjectName .equals (joinVar )) {
1356+ return false ;
1357+ }
1358+ hasSubject = true ;
1359+ }
1360+ return hasSubject ;
1361+ }
1362+
13001363 private boolean introducesJoinVariable (long previousMask , int factorIndex ) {
13011364 long previousVariables = variablesMask (previousMask );
13021365 return (joinVarMasks [factorIndex ] & ~previousVariables ) != 0L ;
0 commit comments