Search in sources :

Example 1 with RecordQueryPlan

use of com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan in project fdb-record-layer by FoundationDB.

the class RecordQueryPlanner method planIntersection.

@Nullable
private ScoredPlan planIntersection(@Nonnull List<ScoredPlan> intersectionCandidates, @Nonnull KeyExpression comparisonKey) {
    // Prefer plans that handle more filters (leave fewer unhandled), more index filters
    intersectionCandidates.sort(Comparator.comparingInt(ScoredPlan::getNumNonSargables).thenComparing(Comparator.comparingInt(ScoredPlan::getNumIndexFilters).reversed()));
    // Since we limited to isPrimaryKeyOrdered(), comparisonKey will always work.
    ScoredPlan plan1 = intersectionCandidates.get(0);
    List<QueryComponent> nonSargables = new ArrayList<>(plan1.combineNonSargables());
    Set<RankComparisons.RankComparison> includedRankComparisons = mergeRankComparisons(null, plan1.includedRankComparisons);
    RecordQueryPlan plan = plan1.plan;
    List<RecordQueryPlan> includedPlans = new ArrayList<>(intersectionCandidates.size());
    includedPlans.add(plan);
    // TODO optimize so that we don't do excessive intersections
    for (int i = 1; i < intersectionCandidates.size(); i++) {
        ScoredPlan nextPlan = intersectionCandidates.get(i);
        List<QueryComponent> nextNonSargables = new ArrayList<>(nextPlan.combineNonSargables());
        int oldCount = nonSargables.size();
        nonSargables.retainAll(nextNonSargables);
        if (nonSargables.size() < oldCount) {
            if (plan.isReverse() != nextPlan.plan.isReverse()) {
                // Cannot intersect plans with incompatible reverse settings.
                return null;
            }
            includedPlans.add(nextPlan.plan);
        }
        includedRankComparisons = mergeRankComparisons(includedRankComparisons, nextPlan.includedRankComparisons);
    }
    if (includedPlans.size() > 1) {
        // Calculating the new score would require more state, not doing, because we currently ignore the score
        // after this call.
        final RecordQueryPlan intersectionPlan = RecordQueryIntersectionPlan.from(includedPlans, comparisonKey);
        if (intersectionPlan.getComplexity() > configuration.getComplexityThreshold()) {
            throw new RecordQueryPlanComplexityException(intersectionPlan);
        }
        return new ScoredPlan(intersectionPlan, nonSargables, Collections.emptyList(), plan1.score, plan1.createsDuplicates, includedRankComparisons);
    } else {
        return null;
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) ArrayList(java.util.ArrayList) Nullable(javax.annotation.Nullable)

Example 2 with RecordQueryPlan

use of com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan in project fdb-record-layer by FoundationDB.

the class RecordQueryPlanner method planRankWithAnd.

@Nullable
private ScoredPlan planRankWithAnd(@Nonnull CandidateScan candidateScan, @Nonnull Index index, @Nonnull GroupingKeyExpression indexExpr, @Nonnull AndComponent and) {
    final List<QueryComponent> filters = and.getChildren();
    for (QueryComponent filter : filters) {
        if (filter instanceof QueryRecordFunctionWithComparison) {
            final QueryRecordFunctionWithComparison filterComparison = (QueryRecordFunctionWithComparison) filter;
            final RankComparisons.RankComparison rankComparison = candidateScan.planContext.rankComparisons.getPlanComparison(filterComparison);
            if (rankComparison != null && rankComparison.getIndex() == index && RankComparisons.matchesSort(indexExpr, candidateScan.planContext.query.getSort())) {
                ScanComparisons scanComparisons = rankComparison.getScanComparisons();
                final Set<RankComparisons.RankComparison> includedRankComparisons = new HashSet<>();
                includedRankComparisons.add(rankComparison);
                final List<QueryComponent> unsatisfiedFilters = new ArrayList<>(filters);
                unsatisfiedFilters.remove(filter);
                unsatisfiedFilters.removeAll(rankComparison.getGroupFilters());
                for (int i = 0; i < unsatisfiedFilters.size(); i++) {
                    final QueryComponent otherFilter = unsatisfiedFilters.get(i);
                    if (otherFilter instanceof QueryRecordFunctionWithComparison) {
                        final QueryRecordFunctionWithComparison otherComparison = (QueryRecordFunctionWithComparison) otherFilter;
                        final RankComparisons.RankComparison otherRank = candidateScan.planContext.rankComparisons.getPlanComparison(otherComparison);
                        if (otherRank != null) {
                            ScanComparisons mergedScanComparisons = scanComparisons.merge(otherRank.getScanComparisons());
                            if (mergedScanComparisons != null) {
                                scanComparisons = mergedScanComparisons;
                                includedRankComparisons.add(otherRank);
                                unsatisfiedFilters.remove(i--);
                            }
                        }
                    }
                }
                final RecordQueryPlan scan = rankScan(candidateScan, filterComparison, scanComparisons);
                final boolean createsDuplicates = RankComparisons.createsDuplicates(index, indexExpr);
                return new ScoredPlan(scan, unsatisfiedFilters, Collections.emptyList(), indexExpr.getColumnSize(), createsDuplicates, includedRankComparisons);
            }
        }
    }
    return null;
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) QueryRecordFunctionWithComparison(com.apple.foundationdb.record.query.expressions.QueryRecordFunctionWithComparison) RankComparisons(com.apple.foundationdb.record.query.plan.planning.RankComparisons) ArrayList(java.util.ArrayList) TimeWindowScanComparisons(com.apple.foundationdb.record.provider.foundationdb.leaderboard.TimeWindowScanComparisons) IndexScanComparisons(com.apple.foundationdb.record.provider.foundationdb.IndexScanComparisons) HashSet(java.util.HashSet) Nullable(javax.annotation.Nullable)

Example 3 with RecordQueryPlan

use of com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan in project fdb-record-layer by FoundationDB.

the class RecordQueryPlanner method planUnorderedUnion.

@Nullable
private ScoredPlan planUnorderedUnion(@Nonnull PlanContext planContext, @Nonnull List<ScoredPlan> subplans) {
    final KeyExpression sort = planContext.query.getSort();
    if (sort != null) {
        return null;
    }
    List<RecordQueryPlan> childPlans = new ArrayList<>(subplans.size());
    Set<RankComparisons.RankComparison> includedRankComparisons = null;
    for (ScoredPlan subplan : subplans) {
        childPlans.add(subplan.plan);
        includedRankComparisons = mergeRankComparisons(includedRankComparisons, subplan.includedRankComparisons);
    }
    final RecordQueryUnorderedUnionPlan unionPlan = RecordQueryUnorderedUnionPlan.from(childPlans);
    if (unionPlan.getComplexity() > configuration.getComplexityThreshold()) {
        throw new RecordQueryPlanComplexityException(unionPlan);
    }
    return new ScoredPlan(unionPlan, Collections.emptyList(), Collections.emptyList(), 1, true, includedRankComparisons);
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) RecordTypeKeyExpression(com.apple.foundationdb.record.metadata.expressions.RecordTypeKeyExpression) VersionKeyExpression(com.apple.foundationdb.record.metadata.expressions.VersionKeyExpression) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) FieldKeyExpression(com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression) NestingKeyExpression(com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression) EmptyKeyExpression(com.apple.foundationdb.record.metadata.expressions.EmptyKeyExpression) ThenKeyExpression(com.apple.foundationdb.record.metadata.expressions.ThenKeyExpression) ArrayList(java.util.ArrayList) RecordQueryUnorderedUnionPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryUnorderedUnionPlan) Nullable(javax.annotation.Nullable)

Example 4 with RecordQueryPlan

use of com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan in project fdb-record-layer by FoundationDB.

the class RecordQueryPlanner method handleNonSargables.

@Nonnull
private ScoredPlan handleNonSargables(@Nonnull ScoredPlan bestPlan, @Nonnull List<ScoredPlan> intersectionCandidates, @Nonnull PlanContext planContext) {
    if (planContext.commonPrimaryKey != null && !intersectionCandidates.isEmpty()) {
        KeyExpression comparisonKey = planContext.commonPrimaryKey;
        final KeyExpression sort = planContext.query.getSort();
        comparisonKey = getKeyForMerge(sort, comparisonKey);
        ScoredPlan intersectionPlan = planIntersection(intersectionCandidates, comparisonKey);
        if (intersectionPlan != null) {
            if (intersectionPlan.unsatisfiedFilters.isEmpty()) {
                return intersectionPlan;
            } else if (bestPlan.getNumNonSargables() > intersectionPlan.getNumNonSargables()) {
                bestPlan = intersectionPlan;
            }
        }
    }
    if (bestPlan.getNumNonSargables() > 0) {
        final RecordQueryPlan filtered = new RecordQueryFilterPlan(bestPlan.plan, planContext.rankComparisons.planComparisonSubstitutes(bestPlan.combineNonSargables()));
        // TODO: further optimization requires knowing which filters are satisfied
        return new ScoredPlan(filtered, Collections.emptyList(), Collections.emptyList(), bestPlan.score, bestPlan.createsDuplicates, bestPlan.includedRankComparisons);
    } else {
        return bestPlan;
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) RecordQueryFilterPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan) RecordTypeKeyExpression(com.apple.foundationdb.record.metadata.expressions.RecordTypeKeyExpression) VersionKeyExpression(com.apple.foundationdb.record.metadata.expressions.VersionKeyExpression) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) FieldKeyExpression(com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression) NestingKeyExpression(com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression) EmptyKeyExpression(com.apple.foundationdb.record.metadata.expressions.EmptyKeyExpression) ThenKeyExpression(com.apple.foundationdb.record.metadata.expressions.ThenKeyExpression) Nonnull(javax.annotation.Nonnull)

Example 5 with RecordQueryPlan

use of com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan in project fdb-record-layer by FoundationDB.

the class RecordQueryPlanner method planFilterWithInJoin.

private ScoredPlan planFilterWithInJoin(@Nonnull PlanContext planContext, @Nonnull InExtractor inExtractor, boolean needOrdering) {
    final ScoredPlan bestPlan = planFilterForInJoin(planContext, inExtractor.subFilter(), needOrdering);
    if (bestPlan != null) {
        final RecordQueryPlan wrapped = inExtractor.wrap(planContext.rankComparisons.wrap(bestPlan.plan, bestPlan.includedRankComparisons, metaData));
        final ScoredPlan scoredPlan = new ScoredPlan(bestPlan.score, wrapped);
        if (needOrdering) {
            scoredPlan.planOrderingKey = inExtractor.adjustOrdering(bestPlan.planOrderingKey, false);
        }
        return scoredPlan;
    }
    return null;
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan)

Aggregations

RecordQueryPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan)373 RecordQuery (com.apple.foundationdb.record.query.RecordQuery)265 FDBRecordContext (com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext)245 Test (org.junit.jupiter.api.Test)228 FDBQueriedRecord (com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord)174 Message (com.google.protobuf.Message)167 Query (com.apple.foundationdb.record.query.expressions.Query)123 Tags (com.apple.test.Tags)121 Tag (org.junit.jupiter.api.Tag)121 Index (com.apple.foundationdb.record.metadata.Index)119 RecordQueryPlanner (com.apple.foundationdb.record.query.plan.RecordQueryPlanner)118 Assertions.assertEquals (org.junit.jupiter.api.Assertions.assertEquals)118 QueryComponent (com.apple.foundationdb.record.query.expressions.QueryComponent)117 List (java.util.List)114 MatcherAssert.assertThat (org.hamcrest.MatcherAssert.assertThat)114 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)113 Expressions.field (com.apple.foundationdb.record.metadata.Key.Expressions.field)107 Arrays (java.util.Arrays)107 Collections (java.util.Collections)106 ArrayList (java.util.ArrayList)100