Search in sources :

Example 6 with RecordQueryFetchFromPartialRecordPlan

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

the class FilterVisitor method postVisit.

@Nonnull
@Override
public RecordQueryPlan postVisit(@Nonnull RecordQueryPlan recordQueryPlan) {
    if (recordQueryPlan instanceof RecordQueryFilterPlan) {
        final RecordQueryFilterPlan filterPlan = (RecordQueryFilterPlan) recordQueryPlan;
        final List<QueryComponent> filters = filterPlan.getFilters();
        final AvailableFields availableFields = availableFields(((RecordQueryFilterPlan) recordQueryPlan).getInnerPlan());
        // Partition the filters according to whether they can be evaluated using just the fields from the index or
        // if they need a full record.
        final List<QueryComponent> indexFilters = Lists.newArrayListWithCapacity(filters.size());
        final List<QueryComponent> residualFilters = Lists.newArrayListWithCapacity(filters.size());
        final Set<KeyExpression> allReferencedFields = new HashSet<>();
        partitionFilters(filters, availableFields, indexFilters, residualFilters, allReferencedFields);
        Verify.verify(indexFilters.size() + residualFilters.size() == filters.size());
        if (indexFilters.isEmpty()) {
            return recordQueryPlan;
        }
        @Nullable RecordQueryPlan removedFetchPlan = removeIndexFetch(filterPlan.getChild(), allReferencedFields);
        if (removedFetchPlan == null) {
            return recordQueryPlan;
        }
        recordQueryPlan = new RecordQueryFetchFromPartialRecordPlan(new RecordQueryFilterPlan(removedFetchPlan, indexFilters), TranslateValueFunction.unableToTranslate());
        if (!residualFilters.isEmpty()) {
            recordQueryPlan = new RecordQueryFilterPlan(recordQueryPlan, residualFilters);
        }
    }
    return recordQueryPlan;
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) AvailableFields(com.apple.foundationdb.record.query.plan.AvailableFields) RecordQueryFilterPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan) RecordQueryFetchFromPartialRecordPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFetchFromPartialRecordPlan) FunctionKeyExpression(com.apple.foundationdb.record.metadata.expressions.FunctionKeyExpression) LiteralKeyExpression(com.apple.foundationdb.record.metadata.expressions.LiteralKeyExpression) FieldKeyExpression(com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) QueryableKeyExpression(com.apple.foundationdb.record.metadata.expressions.QueryableKeyExpression) ThenKeyExpression(com.apple.foundationdb.record.metadata.expressions.ThenKeyExpression) Nullable(javax.annotation.Nullable) HashSet(java.util.HashSet) Nonnull(javax.annotation.Nonnull)

Example 7 with RecordQueryFetchFromPartialRecordPlan

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

the class IntersectionVisitor method postVisit.

@Nonnull
@Override
public RecordQueryPlan postVisit(@Nonnull final RecordQueryPlan recordQueryPlan) {
    if (recordQueryPlan instanceof RecordQueryIntersectionPlan) {
        RecordQueryIntersectionPlan intersectionPlan = (RecordQueryIntersectionPlan) recordQueryPlan;
        Set<KeyExpression> requiredFields = intersectionPlan.getRequiredFields();
        List<RecordQueryPlan> newChildren = new ArrayList<>(intersectionPlan.getChildren().size());
        for (RecordQueryPlan plan : intersectionPlan.getChildren()) {
            @Nullable RecordQueryPlan newPlan = removeIndexFetch(plan, requiredFields);
            if (newPlan == null) {
                // can't remove index fetch, so give up
                return recordQueryPlan;
            }
            newChildren.add(newPlan);
        }
        return new RecordQueryFetchFromPartialRecordPlan(RecordQueryIntersectionPlan.from(newChildren, intersectionPlan.getComparisonKey()), TranslateValueFunction.unableToTranslate());
    }
    return recordQueryPlan;
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) RecordQueryFetchFromPartialRecordPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFetchFromPartialRecordPlan) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) ArrayList(java.util.ArrayList) Nullable(javax.annotation.Nullable) RecordQueryIntersectionPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIntersectionPlan) Nonnull(javax.annotation.Nonnull)

Example 8 with RecordQueryFetchFromPartialRecordPlan

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

the class ValueIndexScanMatchCandidate method tryFetchCoveringIndexScan.

@Nonnull
private Optional<RelationalExpression> tryFetchCoveringIndexScan(@Nonnull final PartialMatch partialMatch, @Nonnull final List<ComparisonRange> comparisonRanges, final boolean isReverse) {
    if (recordTypes.size() > 1) {
        return Optional.empty();
    }
    final RecordType recordType = Iterables.getOnlyElement(recordTypes);
    final IndexKeyValueToPartialRecord.Builder builder = IndexKeyValueToPartialRecord.newBuilder(recordType);
    for (int i = 0; i < indexKeyValues.size(); i++) {
        final Value keyValue = indexKeyValues.get(i);
        if (keyValue instanceof FieldValue && keyValue.isFunctionallyDependentOn(recordValue)) {
            final AvailableFields.FieldData fieldData = AvailableFields.FieldData.of(IndexKeyValueToPartialRecord.TupleSource.KEY, i);
            addCoveringField(builder, (FieldValue) keyValue, fieldData);
        }
    }
    for (int i = 0; i < indexValueValues.size(); i++) {
        final Value valueValue = indexValueValues.get(i);
        if (valueValue instanceof FieldValue && valueValue.isFunctionallyDependentOn(recordValue)) {
            final AvailableFields.FieldData fieldData = AvailableFields.FieldData.of(IndexKeyValueToPartialRecord.TupleSource.VALUE, i);
            addCoveringField(builder, (FieldValue) valueValue, fieldData);
        }
    }
    if (!builder.isValid()) {
        return Optional.empty();
    }
    final IndexScanParameters scanParameters = IndexScanComparisons.byValue(toScanComparisons(comparisonRanges));
    final RecordQueryPlanWithIndex indexPlan = new RecordQueryIndexPlan(index.getName(), scanParameters, isReverse, false, (ValueIndexScanMatchCandidate) partialMatch.getMatchCandidate());
    final RecordQueryCoveringIndexPlan coveringIndexPlan = new RecordQueryCoveringIndexPlan(indexPlan, recordType.getName(), // not used except for old planner properties
    AvailableFields.NO_FIELDS, builder.build());
    return Optional.of(new RecordQueryFetchFromPartialRecordPlan(coveringIndexPlan, coveringIndexPlan::pushValueThroughFetch));
}
Also used : IndexScanParameters(com.apple.foundationdb.record.provider.foundationdb.IndexScanParameters) IndexKeyValueToPartialRecord(com.apple.foundationdb.record.query.plan.IndexKeyValueToPartialRecord) RecordQueryIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan) RecordQueryCoveringIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryCoveringIndexPlan) AvailableFields(com.apple.foundationdb.record.query.plan.AvailableFields) RecordQueryFetchFromPartialRecordPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFetchFromPartialRecordPlan) RecordType(com.apple.foundationdb.record.metadata.RecordType) QuantifiedValue(com.apple.foundationdb.record.query.predicates.QuantifiedValue) FieldValue(com.apple.foundationdb.record.query.predicates.FieldValue) Value(com.apple.foundationdb.record.query.predicates.Value) QuantifiedColumnValue(com.apple.foundationdb.record.query.predicates.QuantifiedColumnValue) RecordQueryPlanWithIndex(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlanWithIndex) FieldValue(com.apple.foundationdb.record.query.predicates.FieldValue) Nonnull(javax.annotation.Nonnull)

Example 9 with RecordQueryFetchFromPartialRecordPlan

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

the class PushSetOperationThroughFetchRule method onMatch.

@Override
@SuppressWarnings("java:S1905")
public void onMatch(@Nonnull PlannerRuleCall call) {
    final PlannerBindings bindings = call.getBindings();
    final RecordQuerySetPlan setOperationPlan = bindings.get(getMatcher());
    final List<? extends Quantifier.Physical> quantifiersOverFetches = bindings.getAll(quantifierOverFetchMatcher);
    // if set operation is dynamic all quantifiers must have fetches
    if (setOperationPlan.isDynamic()) {
        if (quantifiersOverFetches.size() < setOperationPlan.getQuantifiers().size()) {
            return;
        }
    } else {
        if (quantifiersOverFetches.size() <= 1) {
            // pulling up the fetch is meaningless in this case
            return;
        }
    }
    final List<? extends RecordQueryFetchFromPartialRecordPlan> fetchPlans = bindings.getAll(fetchPlanMatcher);
    final ImmutableList<TranslateValueFunction> dependentFunctions = fetchPlans.stream().map(RecordQueryFetchFromPartialRecordPlan::getPushValueFunction).collect(ImmutableList.toImmutableList());
    Verify.verify(quantifiersOverFetches.size() == fetchPlans.size());
    Verify.verify(fetchPlans.size() == dependentFunctions.size());
    final List<? extends Value> requiredValues = setOperationPlan.getRequiredValues(CorrelationIdentifier.uniqueID());
    final Set<CorrelationIdentifier> pushableAliases = setOperationPlan.tryPushValues(dependentFunctions, quantifiersOverFetches, requiredValues);
    // if set operation is dynamic all aliases must be pushable
    if (setOperationPlan.isDynamic()) {
        if (pushableAliases.size() < setOperationPlan.getQuantifiers().size()) {
            return;
        }
    } else {
        if (pushableAliases.size() <= 1) {
            // pulling up the fetch is meaningless in this case
            return;
        }
    }
    final ImmutableList.Builder<Quantifier.Physical> pushableQuantifiersBuilder = ImmutableList.builder();
    final ImmutableList.Builder<RecordQueryFetchFromPartialRecordPlan> pushableFetchPlansBuilder = ImmutableList.builder();
    final ImmutableList.Builder<TranslateValueFunction> pushableDependentFunctionsBuilder = ImmutableList.builder();
    for (int i = 0; i < quantifiersOverFetches.size(); i++) {
        final Quantifier.Physical quantifier = quantifiersOverFetches.get(i);
        if (pushableAliases.contains(quantifier.getAlias())) {
            pushableQuantifiersBuilder.add(quantifier);
            pushableFetchPlansBuilder.add(fetchPlans.get(i));
            pushableDependentFunctionsBuilder.add(dependentFunctions.get(i));
        }
    }
    final ImmutableList<Quantifier.Physical> pushableQuantifiers = pushableQuantifiersBuilder.build();
    final ImmutableList<RecordQueryFetchFromPartialRecordPlan> pushableFetchPlans = pushableFetchPlansBuilder.build();
    final ImmutableList<TranslateValueFunction> pushableDependentFunctions = pushableDependentFunctionsBuilder.build();
    final ImmutableList<Quantifier.Physical> nonPushableQuantifiers = setOperationPlan.getQuantifiers().stream().map(quantifier -> (Quantifier.Physical) quantifier).filter(quantifier -> !pushableAliases.contains(quantifier.getAlias())).collect(ImmutableList.toImmutableList());
    final List<? extends ExpressionRef<RecordQueryPlan>> newPushedInnerPlans = pushableFetchPlans.stream().map(RecordQueryFetchFromPartialRecordPlan::getChild).map(GroupExpressionRef::of).collect(ImmutableList.toImmutableList());
    Verify.verify(pushableQuantifiers.size() + nonPushableQuantifiers.size() == setOperationPlan.getQuantifiers().size());
    final TranslateValueFunction combinedTranslateValueFunction = setOperationPlan.pushValueFunction(pushableDependentFunctions);
    final RecordQuerySetPlan newSetOperationPlan = setOperationPlan.withChildrenReferences(newPushedInnerPlans);
    final RecordQueryFetchFromPartialRecordPlan newFetchPlan = new RecordQueryFetchFromPartialRecordPlan(newSetOperationPlan, combinedTranslateValueFunction);
    if (nonPushableQuantifiers.isEmpty()) {
        call.yield(GroupExpressionRef.of(newFetchPlan));
    } else {
        final List<ExpressionRef<? extends RecordQueryPlan>> newFetchPlanAndResidualInners = Streams.concat(Stream.of(GroupExpressionRef.of(newFetchPlan)), nonPushableQuantifiers.stream().map(Quantifier.Physical::getRangesOver).map(RecordQueryPlan::narrowReference)).collect(ImmutableList.toImmutableList());
        call.yield(GroupExpressionRef.of(setOperationPlan.withChildrenReferences(newFetchPlanAndResidualInners)));
    }
}
Also used : TranslateValueFunction(com.apple.foundationdb.record.query.plan.plans.TranslateValueFunction) PlannerRuleCall(com.apple.foundationdb.record.query.plan.temp.PlannerRuleCall) RecordQueryFetchFromPartialRecordPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFetchFromPartialRecordPlan) PlannerRule(com.apple.foundationdb.record.query.plan.temp.PlannerRule) Quantifier(com.apple.foundationdb.record.query.plan.temp.Quantifier) RecordQueryPlanMatchers.anyPlan(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.anyPlan) GroupExpressionRef(com.apple.foundationdb.record.query.plan.temp.GroupExpressionRef) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) RecordQueryPlanMatchers.fetchFromPartialRecordPlan(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.fetchFromPartialRecordPlan) ImmutableList(com.google.common.collect.ImmutableList) RelationalExpressionMatchers.ofTypeOwning(com.apple.foundationdb.record.query.plan.temp.matchers.RelationalExpressionMatchers.ofTypeOwning) ExpressionRef(com.apple.foundationdb.record.query.plan.temp.ExpressionRef) MultiMatcher.some(com.apple.foundationdb.record.query.plan.temp.matchers.MultiMatcher.some) Nonnull(javax.annotation.Nonnull) Verify(com.google.common.base.Verify) RecordQuerySetPlan(com.apple.foundationdb.record.query.plan.plans.RecordQuerySetPlan) QuantifierMatchers.physicalQuantifier(com.apple.foundationdb.record.query.plan.temp.matchers.QuantifierMatchers.physicalQuantifier) Set(java.util.Set) PlannerBindings(com.apple.foundationdb.record.query.plan.temp.matchers.PlannerBindings) Streams(com.google.common.collect.Streams) Value(com.apple.foundationdb.record.query.predicates.Value) List(java.util.List) BindingMatcher(com.apple.foundationdb.record.query.plan.temp.matchers.BindingMatcher) Stream(java.util.stream.Stream) CorrelationIdentifier(com.apple.foundationdb.record.query.plan.temp.CorrelationIdentifier) API(com.apple.foundationdb.annotation.API) ImmutableList(com.google.common.collect.ImmutableList) GroupExpressionRef(com.apple.foundationdb.record.query.plan.temp.GroupExpressionRef) ExpressionRef(com.apple.foundationdb.record.query.plan.temp.ExpressionRef) PlannerBindings(com.apple.foundationdb.record.query.plan.temp.matchers.PlannerBindings) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) TranslateValueFunction(com.apple.foundationdb.record.query.plan.plans.TranslateValueFunction) RecordQueryFetchFromPartialRecordPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFetchFromPartialRecordPlan) RecordQuerySetPlan(com.apple.foundationdb.record.query.plan.plans.RecordQuerySetPlan) CorrelationIdentifier(com.apple.foundationdb.record.query.plan.temp.CorrelationIdentifier) Quantifier(com.apple.foundationdb.record.query.plan.temp.Quantifier) QuantifierMatchers.physicalQuantifier(com.apple.foundationdb.record.query.plan.temp.matchers.QuantifierMatchers.physicalQuantifier)

Example 10 with RecordQueryFetchFromPartialRecordPlan

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

the class MergeProjectionAndFetchRule method onMatch.

@Override
public void onMatch(@Nonnull PlannerRuleCall call) {
    final LogicalProjectionExpression projectionExpression = call.get(root);
    // if the fetch is able to push all values we can eliminate the fetch as well
    final RecordQueryFetchFromPartialRecordPlan fetchPlan = call.get(innerPlanMatcher);
    final CorrelationIdentifier newInnerAlias = CorrelationIdentifier.uniqueID();
    final List<? extends Value> resultValues = projectionExpression.getResultValues();
    final boolean allPushable = resultValues.stream().allMatch(value -> fetchPlan.pushValue(value, newInnerAlias).isPresent());
    if (allPushable) {
        // all fields in the projection are already available underneath the fetch
        // we don't need the projection nor the fetch
        call.yield(call.ref(fetchPlan.getChild()));
    }
}
Also used : RecordQueryFetchFromPartialRecordPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFetchFromPartialRecordPlan) CorrelationIdentifier(com.apple.foundationdb.record.query.plan.temp.CorrelationIdentifier) LogicalProjectionExpression(com.apple.foundationdb.record.query.plan.temp.expressions.LogicalProjectionExpression)

Aggregations

RecordQueryFetchFromPartialRecordPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryFetchFromPartialRecordPlan)12 RecordQueryPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan)8 Nonnull (javax.annotation.Nonnull)8 Nullable (javax.annotation.Nullable)6 KeyExpression (com.apple.foundationdb.record.metadata.expressions.KeyExpression)4 CorrelationIdentifier (com.apple.foundationdb.record.query.plan.temp.CorrelationIdentifier)4 PlannerBindings (com.apple.foundationdb.record.query.plan.temp.matchers.PlannerBindings)4 RecordType (com.apple.foundationdb.record.metadata.RecordType)3 AvailableFields (com.apple.foundationdb.record.query.plan.AvailableFields)3 RecordQueryPlanWithIndex (com.apple.foundationdb.record.query.plan.plans.RecordQueryPlanWithIndex)3 TranslateValueFunction (com.apple.foundationdb.record.query.plan.plans.TranslateValueFunction)3 GroupExpressionRef (com.apple.foundationdb.record.query.plan.temp.GroupExpressionRef)3 Quantifier (com.apple.foundationdb.record.query.plan.temp.Quantifier)3 Value (com.apple.foundationdb.record.query.predicates.Value)3 List (java.util.List)3 API (com.apple.foundationdb.annotation.API)2 Index (com.apple.foundationdb.record.metadata.Index)2 QueryComponent (com.apple.foundationdb.record.query.expressions.QueryComponent)2 IndexKeyValueToPartialRecord (com.apple.foundationdb.record.query.plan.IndexKeyValueToPartialRecord)2 RecordQueryCoveringIndexPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryCoveringIndexPlan)2