@@ -71,6 +71,7 @@ final class SketchJoinOrderPlanner {
7171 private static final double FILTERED_SEED_MAX_STEP_WORK_RATIO = 12.0d ;
7272 private static final double SEED_FILTER_ROW_FLOW_MAX_PASS_RATIO = 0.25d ;
7373 private static final double BROAD_BRIDGE_ENDPOINT_PREP_MIN_RATIO = 3.0d ;
74+ private static final double FINITE_DOMAIN_PREFIX_GUARD_MIN_ACCESS_ROWS = 1_000.0d ;
7475 private static final int FINITE_DOMAIN_FILTER_MAX_ENUMERATED_BINDINGS = 4096 ;
7576 private static final int COMPLETED_DEFERRED_FILTER_CONNECTIONS = 2 ;
7677 private static final double DEFERRED_FILTER_ORDERING_MAX_PASS_RATIO = 0.5d ;
@@ -874,6 +875,12 @@ private StatePlan seedPlan(int factorIndex) {
874875 if (!isFactorActionLegal (factorIndex , initiallyBoundVarMask )) {
875876 return null ;
876877 }
878+ if (shouldDelayUnfilteredFiniteSeed (factorIndex )) {
879+ return null ;
880+ }
881+ if (shouldDelayFiniteLookupGuardedSeed (factorIndex )) {
882+ return null ;
883+ }
877884 long seedMask = bit (factorIndex );
878885 PlanFactor factor = factors .get (factorIndex );
879886 SketchBasedJoinEstimator .TuplePlanEstimate conditionedEstimate = conditionedFactorEstimate (factorIndex ,
@@ -956,6 +963,63 @@ private StatePlan seedPlan(int factorIndex) {
956963 return applyAutomaticFilterActions (seed );
957964 }
958965
966+ private boolean shouldDelayUnfilteredFiniteSeed (int factorIndex ) {
967+ if (!isSmallBindingSetAssignment (factorIndex )) {
968+ return false ;
969+ }
970+ long seedVars = bindingVarMasks [factorIndex ] & variableUniverseMask ;
971+ if (finiteFilterParticipationCount (seedVars ) > 0 ) {
972+ return false ;
973+ }
974+ long assignments = smallBindingSetAssignmentFactorMask & ~bit (factorIndex );
975+ while (assignments != 0L ) {
976+ int assignment = Long .numberOfTrailingZeros (assignments );
977+ assignments &= assignments - 1L ;
978+ if (finiteFilterParticipationCount (bindingVarMasks [assignment ] & variableUniverseMask ) > 0 ) {
979+ return true ;
980+ }
981+ }
982+ return false ;
983+ }
984+
985+ private boolean shouldDelayFiniteLookupGuardedSeed (int factorIndex ) {
986+ if (isBindingSetAssignment (factorIndex ) || statementPatternFactor (factorIndex ) == null ) {
987+ return false ;
988+ }
989+ long pendingAssignments = smallBindingSetAssignmentFactorMask ;
990+ if (pendingAssignments == 0L ) {
991+ return false ;
992+ }
993+ long legalAssignments = 0L ;
994+ long assignments = pendingAssignments ;
995+ while (assignments != 0L ) {
996+ int assignment = Long .numberOfTrailingZeros (assignments );
997+ assignments &= assignments - 1L ;
998+ if (isFactorActionLegal (assignment , initiallyBoundVarMask )) {
999+ legalAssignments |= bit (assignment );
1000+ }
1001+ }
1002+ if (legalAssignments == 0L ) {
1003+ return false ;
1004+ }
1005+ long pendingAssignmentVars = assignmentVariableMask (legalAssignments ) & ~initiallyBoundVarMask ;
1006+ if (pendingAssignmentVars == 0L ) {
1007+ return false ;
1008+ }
1009+ SketchBasedJoinEstimator .TuplePlanEstimate conditionedEstimate = conditionedFactorEstimate (factorIndex ,
1010+ initiallyBoundVarMask );
1011+ FactorPhysicalEstimate physicalEstimate = factorPhysicalEstimate (factorIndex , 0L , initiallyBoundVarMask ,
1012+ conditionedEstimate .outputRows (), null );
1013+ if (isExactStatementDirectLookup (physicalEstimate )) {
1014+ return false ;
1015+ }
1016+ long missingLookupVars = missingExactLookupVariableMask (factorIndex ,
1017+ physicalEstimate .lookupComponentMask (), initiallyBoundVarMask );
1018+ return (missingLookupVars != 0L && (missingLookupVars & ~pendingAssignmentVars ) == 0L )
1019+ || shouldDelayBroadLookupForFinitePrefixGuard (physicalEstimate , missingLookupVars ,
1020+ pendingAssignmentVars );
1021+ }
1022+
9591023 private boolean appliesSelectiveSeedFilterRowFlow (long seedMask ,
9601024 SketchBasedJoinEstimator .TuplePlanEstimate rowsEnteringEstimate ) {
9611025 double passRatio = newlyUnlockedFilterPassRatio (0L , seedMask , rowsEnteringEstimate );
@@ -2899,7 +2963,141 @@ private boolean isFactorActionLegal(int factorIndex, long boundVarMask) {
28992963 }
29002964
29012965 private long candidateActionsMask (StatePlan plan ) {
2902- return candidatesMask (plan ) | availableFilterActionMask (plan );
2966+ long candidates = candidatesMask (plan );
2967+ candidates = delayFiniteCompletableLookupCandidates (plan , candidates );
2968+ candidates = delayUnfilteredFiniteAssignmentsUntilExactLookupGuards (plan , candidates );
2969+ candidates = preferBoundSubjectTypeGuards (plan .mask (), candidates );
2970+ return candidates | availableFilterActionMask (plan );
2971+ }
2972+
2973+ private long delayFiniteCompletableLookupCandidates (StatePlan plan , long candidates ) {
2974+ long pendingAssignments = candidates & smallBindingSetAssignmentFactorMask ;
2975+ if (pendingAssignments == 0L ) {
2976+ return candidates ;
2977+ }
2978+ long delayed = 0L ;
2979+ long boundVarMask = plan .boundVarMask ();
2980+ long pendingAssignmentVars = assignmentVariableMask (pendingAssignments ) & ~boundVarMask ;
2981+ long statementCandidates = candidates & ~bindingSetAssignmentFactorMask ;
2982+ while (statementCandidates != 0L ) {
2983+ int candidate = Long .numberOfTrailingZeros (statementCandidates );
2984+ statementCandidates &= statementCandidates - 1L ;
2985+ if (statementPatternFactor (candidate ) == null ) {
2986+ continue ;
2987+ }
2988+ FactorPhysicalEstimate physicalEstimate = factorPhysicalEstimate (candidate , plan .mask (), boundVarMask ,
2989+ factorOutputRows [candidate ], plan .estimate ());
2990+ if (isExactStatementDirectLookup (physicalEstimate )) {
2991+ continue ;
2992+ }
2993+ long missingLookupVars = missingExactLookupVariableMask (candidate ,
2994+ physicalEstimate .lookupComponentMask (), boundVarMask );
2995+ if (missingLookupVars != 0L && (missingLookupVars & ~pendingAssignmentVars ) == 0L ) {
2996+ delayed |= bit (candidate );
2997+ continue ;
2998+ }
2999+ if (shouldDelayBroadLookupForFinitePrefixGuard (physicalEstimate , missingLookupVars ,
3000+ pendingAssignmentVars )) {
3001+ delayed |= bit (candidate );
3002+ }
3003+ }
3004+ return candidates & ~delayed ;
3005+ }
3006+
3007+ private boolean shouldDelayBroadLookupForFinitePrefixGuard (FactorPhysicalEstimate physicalEstimate ,
3008+ long missingLookupVars , long pendingAssignmentVars ) {
3009+ if (physicalEstimate == null || missingLookupVars == 0L
3010+ || (missingLookupVars & pendingAssignmentVars ) == 0L
3011+ || isExactStatementDirectLookup (physicalEstimate )) {
3012+ return false ;
3013+ }
3014+ double currentAccessRows = physicalEstimate .accessRowsBeforeFilter ();
3015+ if (!isFiniteNonNegative (currentAccessRows )) {
3016+ currentAccessRows = physicalEstimate .workRows ();
3017+ }
3018+ if (!isFiniteNonNegative (currentAccessRows )) {
3019+ currentAccessRows = physicalEstimate .factorOutputRows ();
3020+ }
3021+ return isFiniteNonNegative (currentAccessRows )
3022+ && currentAccessRows >= FINITE_DOMAIN_PREFIX_GUARD_MIN_ACCESS_ROWS ;
3023+ }
3024+
3025+ private long delayUnfilteredFiniteAssignmentsUntilExactLookupGuards (StatePlan plan , long candidates ) {
3026+ long assignments = candidates & smallBindingSetAssignmentFactorMask ;
3027+ if (assignments == 0L ) {
3028+ return candidates ;
3029+ }
3030+ long unfilteredAssignments = 0L ;
3031+ long filterUnlockingAssignments = 0L ;
3032+ long filterParticipatingAssignments = 0L ;
3033+ long boundVarMask = plan .boundVarMask ();
3034+ long remaining = assignments ;
3035+ while (remaining != 0L ) {
3036+ int assignment = Long .numberOfTrailingZeros (remaining );
3037+ remaining &= remaining - 1L ;
3038+ long assignmentVars = bindingVarMasks [assignment ] & ~boundVarMask ;
3039+ if (assignmentVars == 0L ) {
3040+ continue ;
3041+ }
3042+ if (delayedFiniteFilterCount (boundVarMask , assignmentVars ) > 0 ) {
3043+ filterUnlockingAssignments |= bit (assignment );
3044+ } else if (finiteFilterParticipationCount (assignmentVars ) > 0 ) {
3045+ filterParticipatingAssignments |= bit (assignment );
3046+ } else {
3047+ unfilteredAssignments |= bit (assignment );
3048+ }
3049+ }
3050+ long preferredFiniteAssignments = filterUnlockingAssignments != 0L
3051+ ? filterUnlockingAssignments
3052+ : filterParticipatingAssignments ;
3053+ if (unfilteredAssignments == 0L
3054+ || (preferredFiniteAssignments == 0L && pendingBoundExactLookupGuardMask (plan ) == 0L )) {
3055+ return candidates ;
3056+ }
3057+ return candidates & ~unfilteredAssignments ;
3058+ }
3059+
3060+ private int finiteFilterParticipationCount (long assignmentVars ) {
3061+ if (deferredFilters .isEmpty () || assignmentVars == 0L ) {
3062+ return 0 ;
3063+ }
3064+ int count = 0 ;
3065+ for (int i = 0 ; i < plannedFilterActionCount (); i ++) {
3066+ long requiredVars = deferredFilterRequiredVarMasks [i ];
3067+ if (Long .bitCount (requiredVars ) >= 2 && (requiredVars & assignmentVars ) != 0L ) {
3068+ count ++;
3069+ }
3070+ }
3071+ return count ;
3072+ }
3073+
3074+ private long assignmentVariableMask (long assignmentMask ) {
3075+ long variables = 0L ;
3076+ long assignments = assignmentMask ;
3077+ while (assignments != 0L ) {
3078+ int assignment = Long .numberOfTrailingZeros (assignments );
3079+ assignments &= assignments - 1L ;
3080+ variables |= bindingVarMasks [assignment ] & variableUniverseMask ;
3081+ }
3082+ return variables ;
3083+ }
3084+
3085+ private long missingExactLookupVariableMask (int factorIndex , int lookupComponentMask , long boundVarMask ) {
3086+ StatementPattern statementPattern = statementPatternFactor (factorIndex );
3087+ if (statementPattern == null ) {
3088+ return 0L ;
3089+ }
3090+ long missingVars = 0L ;
3091+ if ((lookupComponentMask & componentBit (SketchBasedJoinEstimator .Component .S )) == 0 ) {
3092+ missingVars |= variableMask (statementPattern .getSubjectVar ()) & ~boundVarMask ;
3093+ }
3094+ if ((lookupComponentMask & componentBit (SketchBasedJoinEstimator .Component .P )) == 0 ) {
3095+ missingVars |= variableMask (statementPattern .getPredicateVar ()) & ~boundVarMask ;
3096+ }
3097+ if ((lookupComponentMask & componentBit (SketchBasedJoinEstimator .Component .O )) == 0 ) {
3098+ missingVars |= variableMask (statementPattern .getObjectVar ()) & ~boundVarMask ;
3099+ }
3100+ return missingVars ;
29033101 }
29043102
29053103 private long availableFilterActionMask (StatePlan plan ) {
@@ -2908,9 +3106,53 @@ private long availableFilterActionMask(StatePlan plan) {
29083106 }
29093107 long filters = eligibleDeferredFilterMask (plan .boundVarMask (), plan .appliedFilterMask (),
29103108 plannedFilterMask & ~automaticFilterMask );
3109+ filters = delayNestedFilterActionsUntilBoundExactLookupGuardsRun (plan , filters );
29113110 return filters << factors .size ();
29123111 }
29133112
3113+ private long delayNestedFilterActionsUntilBoundExactLookupGuardsRun (StatePlan plan , long filters ) {
3114+ if (filters == 0L
3115+ || (pendingSmallBindingAssignmentMask (plan ) == 0L && pendingBoundExactLookupGuardMask (plan ) == 0L )) {
3116+ return filters ;
3117+ }
3118+ long blocked = 0L ;
3119+ long remaining = filters ;
3120+ while (remaining != 0L ) {
3121+ int filterIndex = Long .numberOfTrailingZeros (remaining );
3122+ remaining &= remaining - 1L ;
3123+ if (deferredFilters .get (filterIndex ).hasNestedTupleExpression ()) {
3124+ blocked |= bit (filterIndex );
3125+ }
3126+ }
3127+ return filters & ~blocked ;
3128+ }
3129+
3130+ private long pendingSmallBindingAssignmentMask (StatePlan plan ) {
3131+ return candidatesMask (plan ) & smallBindingSetAssignmentFactorMask ;
3132+ }
3133+
3134+ private long pendingBoundExactLookupGuardMask (StatePlan plan ) {
3135+ long candidates = candidatesMask (plan ) & ~bindingSetAssignmentFactorMask ;
3136+ if (candidates == 0L ) {
3137+ return 0L ;
3138+ }
3139+ long boundVarMask = plan .boundVarMask ();
3140+ long guards = 0L ;
3141+ while (candidates != 0L ) {
3142+ int candidate = Long .numberOfTrailingZeros (candidates );
3143+ candidates &= candidates - 1L ;
3144+ if ((runtimeVarMasks [candidate ] & ~boundVarMask ) != 0L ) {
3145+ continue ;
3146+ }
3147+ FactorPhysicalEstimate physicalEstimate = factorPhysicalEstimate (candidate , plan .mask (), boundVarMask ,
3148+ factorOutputRows [candidate ], plan .estimate ());
3149+ if (isExactStatementDirectLookup (physicalEstimate )) {
3150+ guards |= bit (candidate );
3151+ }
3152+ }
3153+ return guards ;
3154+ }
3155+
29143156 private StatePlan applyAutomaticFilterActions (StatePlan plan ) {
29153157 StatePlan current = plan ;
29163158 while (automaticFilterMask != 0L ) {
@@ -3154,6 +3396,9 @@ private double physicalRowFlowRows(int factorIndex, long mask,
31543396 double rowsPerInvocation = physicalEstimate .accessRowsBeforeFilter ();
31553397 if (!isFiniteNonNegative (rowsPerInvocation )) {
31563398 rowsPerInvocation = physicalEstimate .factorOutputRows ();
3399+ } else if (physicalEstimate .missingLookupComponents () > 0
3400+ && isFiniteNonNegative (physicalEstimate .factorOutputRows ())) {
3401+ rowsPerInvocation = Math .max (rowsPerInvocation , physicalEstimate .factorOutputRows ());
31573402 }
31583403 if (!isFiniteNonNegative (rowsPerInvocation ) || rowsPerInvocation <= 0.0d ) {
31593404 return Double .NaN ;
@@ -3224,6 +3469,16 @@ private boolean isExactStatementDirectLookup(SketchBasedJoinEstimator.AccessShap
32243469 && accessShape .isDirectLookup (lookupBoundComponentMask );
32253470 }
32263471
3472+ private boolean isExactStatementDirectLookup (FactorPhysicalEstimate physicalEstimate ) {
3473+ if (physicalEstimate == null || !physicalEstimate .directLookup ()) {
3474+ return false ;
3475+ }
3476+ int exactStatementMask = componentBit (SketchBasedJoinEstimator .Component .S )
3477+ | componentBit (SketchBasedJoinEstimator .Component .P )
3478+ | componentBit (SketchBasedJoinEstimator .Component .O );
3479+ return (physicalEstimate .lookupComponentMask () & exactStatementMask ) == exactStatementMask ;
3480+ }
3481+
32273482 private int componentBit (SketchBasedJoinEstimator .Component component ) {
32283483 return 1 << component .ordinal ();
32293484 }
@@ -6021,6 +6276,9 @@ private void addPhysicalMetrics(Map<String, String> stringMetrics, Map<String, D
60216276 }
60226277 stringMetrics .putAll (factorCostEstimate .getStringMetrics ());
60236278 doubleMetrics .putAll (factorCostEstimate .getDoubleMetrics ());
6279+ if (physicalEstimate .physicalComparable () && isFiniteNonNegative (physicalEstimate .workRows ())) {
6280+ doubleMetrics .put (TelemetryMetricNames .PLANNED_ACCESS_WORK_ROWS , physicalEstimate .workRows ());
6281+ }
60246282 }
60256283
60266284 private Set <String > sharedJoinVars (TupleExpr tupleExpr , Set <String > boundBefore ) {
0 commit comments