@@ -73,6 +73,7 @@ final class LmdbSketchJoinOptimizer implements QueryOptimizer {
7373
7474 private static final double FINITE_BINDING_GUARD_PRODUCT_LIMIT = 5000.0d ;
7575 private static final double CANONICAL_FINITE_ANCHOR_SELECTIVE_FILTER_PASS_RATIO = 0.75d ;
76+ private static final int CANONICAL_FINITE_ANCHOR_LITERAL_FILTER_SCORE = 50 ;
7677 private static final int CANONICAL_FINITE_ANCHOR_ULTRA_SELECTIVE_FILTER_SCORE = 950 ;
7778 private static final int CORRELATED_ANTI_JOIN_COMPLEX_SUFFIX_PATTERN_LIMIT = 3 ;
7879 private static final String FINITE_ANCHOR_PLANNER_ID = "lmdb-finite-anchor" ;
@@ -1953,6 +1954,11 @@ private Optional<List<TupleExpr>> canonicalFiniteAnchorOrder(List<TupleExpr> seg
19531954 bound .addAll (tupleExpr .getBindingNames ());
19541955 connectedPatterns .add (tupleExpr );
19551956 }
1957+ Set <String > anchorBound = new HashSet <>(boundBeforeSegment );
1958+ for (TupleExpr anchor : anchors ) {
1959+ anchorBound .addAll (anchor .getBindingNames ());
1960+ }
1961+ promoteSubjectTypeGuardsBeforeUnanchoredFanout (connectedPatterns , anchorBound , plannerFilters );
19561962 List <TupleExpr > ordered = new ArrayList <>(segment .size ());
19571963 while (!connectedPatterns .isEmpty ()
19581964 && shouldLeadBeforeFilterOnlyAnchors (connectedPatterns .get (0 ), anchors , boundBeforeSegment ,
@@ -1964,6 +1970,35 @@ && shouldLeadBeforeFilterOnlyAnchors(connectedPatterns.get(0), anchors, boundBef
19641970 return Optional .of (List .copyOf (ordered ));
19651971 }
19661972
1973+ private void promoteSubjectTypeGuardsBeforeUnanchoredFanout (List <TupleExpr > connectedPatterns ,
1974+ Set <String > anchorBound , List <JoinOrderPlanner .FilterConstraint > plannerFilters ) {
1975+ for (int i = 1 ; i < connectedPatterns .size (); i ++) {
1976+ TupleExpr tupleExpr = connectedPatterns .get (i );
1977+ if (!isSubjectTypeGuardPattern (tupleExpr )) {
1978+ continue ;
1979+ }
1980+ Set <String > typeBindings = plannerBindingNames (tupleExpr .getBindingNames ());
1981+ if (!hasCorrelatedNotExistsFilterForTuple (typeBindings , anchorBound , plannerFilters )) {
1982+ continue ;
1983+ }
1984+ int target = i ;
1985+ while (target > 0 ) {
1986+ TupleExpr previous = connectedPatterns .get (target - 1 );
1987+ Set <String > previousBindings = plannerBindingNames (previous .getBindingNames ());
1988+ if (Collections .disjoint (typeBindings , previousBindings )
1989+ || !Collections .disjoint (anchorBound , previousBindings )) {
1990+ break ;
1991+ }
1992+ if (selectiveLocalFilterScoreForPattern (previousBindings , anchorBound ,
1993+ plannerFilters ) >= CANONICAL_FINITE_ANCHOR_ULTRA_SELECTIVE_FILTER_SCORE ) {
1994+ break ;
1995+ }
1996+ Collections .swap (connectedPatterns , target - 1 , target );
1997+ target --;
1998+ }
1999+ }
2000+ }
2001+
19672002 private boolean shouldLeadBeforeFilterOnlyAnchors (TupleExpr tupleExpr , List <TupleExpr > anchors ,
19682003 Set <String > boundBeforeSegment , List <JoinOrderPlanner .FilterConstraint > plannerFilters ) {
19692004 Set <String > tupleBindings = plannerBindingNames (tupleExpr .getBindingNames ());
@@ -2026,9 +2061,13 @@ private int selectCanonicalFiniteAnchorPattern(List<TupleExpr> patterns, Set<Str
20262061 boolean correlatedTypeGuard = subjectTypeGuard
20272062 && hasCorrelatedNotExistsFilterForTuple (tupleBindings , bound , plannerFilters );
20282063 if (directBindingConnection ) {
2029- score += 10_000 + localFilterScore ;
2064+ score += 10_000 ;
2065+ if (connectedPatternCount > 1
2066+ || localFilterScore >= CANONICAL_FINITE_ANCHOR_ULTRA_SELECTIVE_FILTER_SCORE ) {
2067+ score += localFilterScore ;
2068+ }
20302069 } else if (correlatedTypeGuard ) {
2031- score += 12_000 ;
2070+ score += 4_000 ;
20322071 } else if (localFilterScore > 0 ) {
20332072 score += 5_000 + localFilterScore ;
20342073 } else {
@@ -2056,10 +2095,23 @@ private boolean hasCorrelatedNotExistsFilterForTuple(Set<String> tupleBindings,
20562095 && tupleBindings .containsAll (requiredVarsOutsideBound (requiredVars , bound ))) {
20572096 return true ;
20582097 }
2098+ if (filter .getCondition ()
2099+ .map (condition -> conditionConnectsBoundToTuple (condition , tupleBindings , bound ))
2100+ .orElse (false )) {
2101+ return true ;
2102+ }
20592103 }
20602104 return false ;
20612105 }
20622106
2107+ private boolean conditionConnectsBoundToTuple (ValueExpr condition , Set <String > tupleBindings ,
2108+ Set <String > bound ) {
2109+ Set <String > conditionVars = plannerBindingNames (VarNameCollector .process (condition ));
2110+ return !conditionVars .isEmpty ()
2111+ && !Collections .disjoint (conditionVars , bound )
2112+ && !Collections .disjoint (conditionVars , tupleBindings );
2113+ }
2114+
20632115 private boolean isNotExistsFilterConstraint (JoinOrderPlanner .FilterConstraint filter ) {
20642116 return filter .isNotExists ()
20652117 || filter .getCondition ()
@@ -2109,14 +2161,14 @@ private Set<String> requiredVarsOutsideBound(Set<String> requiredVars, Set<Strin
21092161 private int canonicalFilterSelectivityScore (JoinOrderPlanner .FilterConstraint filter ) {
21102162 double passRatio = filter .getEstimatedPassRatio ();
21112163 if (Double .isFinite (passRatio )
2112- && passRatio > 0.0d
2164+ && passRatio >= 0.0d
21132165 && passRatio <= CANONICAL_FINITE_ANCHOR_SELECTIVE_FILTER_PASS_RATIO ) {
21142166 return Math .max (1 , (int ) Math .round ((1.0d - passRatio ) * 1_000.0d ));
21152167 }
21162168 if (filter .getCondition ()
21172169 .map (this ::conditionContainsLiteralConstant )
21182170 .orElse (false )) {
2119- return 1 ;
2171+ return CANONICAL_FINITE_ANCHOR_LITERAL_FILTER_SCORE ;
21202172 }
21212173 return 0 ;
21222174 }
@@ -2144,7 +2196,7 @@ private boolean isSubjectTypeGuardPattern(TupleExpr tupleExpr) {
21442196 Var object = statementPattern .getObjectVar ();
21452197 return predicate != null
21462198 && predicate .hasValue ()
2147- && RDF .TYPE .equals (predicate .getValue ())
2199+ && RDF .TYPE .stringValue (). equals (predicate .getValue (). stringValue ())
21482200 && object != null
21492201 && object .hasValue ();
21502202 }
0 commit comments