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;
}
}
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;
}
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);
}
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;
}
}
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;
}
Aggregations