use of com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan in project fdb-record-layer by FoundationDB.
the class FDBInQueryTest method testInQueryOrDifferentCondition.
/**
* Verify that an IN requires an unordered union due to incompatible ordering.
*/
@DualPlannerTest
void testInQueryOrDifferentCondition() throws Exception {
complexQuerySetup(NO_HOOK);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.or(Query.field("num_value_unique").lessThan(910), Query.and(Query.field("num_value_unique").greaterThan(990), Query.field("num_value_2").in(Arrays.asList(2, 0))))).build();
RecordQueryPlan plan = planner.plan(query);
if (planner instanceof RecordQueryPlanner) {
// Without the join, these would be using the same index and so compatible, even though inequalities.
// TODO: IN join in filter can prevent index scan merging (https://github.com/FoundationDB/fdb-record-layer/issues/9)
assertMatchesExactly(plan, unorderedPrimaryKeyDistinctPlan(unorderedUnionPlan(indexPlan().where(indexName("MySimpleRecord$num_value_unique")).and(scanComparisons(range("([null],[910])"))), inValuesJoinPlan(filterPlan(indexPlan().where(indexName("MySimpleRecord$num_value_unique")).and(scanComparisons(range("([990],>"))))).where(inValuesList(equalsObject(Arrays.asList(0, 2)))))));
assertEquals(-97067043, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(942676960, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(417180157, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
// Cascades planner avoids IN-JOIN causing a primary scan and a UNION-ALL
unionPlan(indexPlan().where(indexName("MySimpleRecord$num_value_unique")).and(scanComparisons(range("([null],[910])"))), predicatesFilterPlan(indexPlan().where(indexName("MySimpleRecord$num_value_unique")).and(scanComparisons(range("([990],>")))).where(predicates(valuePredicate(fieldValue("num_value_2"), new Comparisons.ListComparison(Comparisons.Type.IN, ImmutableList.of(0, 2)))))).where(comparisonKey(concat(field("num_value_unique"), primaryKey("MySimpleRecord"))));
assertEquals(-1933328656, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(1747054907, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1932097284, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
}
assertEquals(16, querySimpleRecordStore(NO_HOOK, plan, EvaluationContext::empty, record -> {
assertThat(record.getNumValueUnique(), anyOf(lessThan(910), greaterThan(990)));
if (record.getNumValue3Indexed() > 990) {
assertThat(record.getNumValue2(), anyOf(is(2), is(0)));
}
}, context -> TestHelpers.assertDiscardedAtMost(13, context)));
}
use of com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan in project fdb-record-layer by FoundationDB.
the class FDBInQueryTest method testInQueryIndexSortedDifferently.
/**
* Verify that an IN against an unsorted list with an index is not implemented as an IN JOIN when the query sort is
* not by the field with an IN filter.
*/
@DualPlannerTest
void testInQueryIndexSortedDifferently() throws Exception {
complexQuerySetup(NO_HOOK);
final QueryComponent filter = Query.field("num_value_3_indexed").in(asList(1, 4, 2));
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(filter).setSort(field("str_value_indexed")).build();
// Index(MySimpleRecord$str_value_indexed <,>) | num_value_3_indexed IN [1, 4, 2]
RecordQueryPlan plan = planner.plan(query);
// IN join is cancelled on account of incompatible sorting.
if (planner instanceof RecordQueryPlanner) {
assertMatchesExactly(plan, filterPlan(selfOrDescendantPlans(indexPlan().where(indexName("MySimpleRecord$str_value_indexed")).and(scanComparisons(unbounded())))).where(queryComponents(exactly(equalsObject(filter)))));
assertEquals(1775865786, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(972267, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(212572525, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertMatchesExactly(plan, predicatesFilterPlan(selfOrDescendantPlans(indexPlan().where(indexName("MySimpleRecord$str_value_indexed")).and(scanComparisons(unbounded())))).where(predicates(valuePredicate(fieldValue("num_value_3_indexed"), new Comparisons.ListComparison(Comparisons.Type.IN, ImmutableList.of(1, 4, 2))))));
assertEquals(1470982333, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(800585401, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(1012185659, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
}
assertEquals(60, querySimpleRecordStore(NO_HOOK, plan, EvaluationContext::empty, record -> assertThat(record.getNumValue3Indexed(), anyOf(is(1), is(2), is(4))), context -> TestHelpers.assertDiscardedAtMost(40, context)));
}
use of com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan in project fdb-record-layer by FoundationDB.
the class FDBInQueryTest method testInQueryOrMultipleIndexes.
/**
* Verify an IN clause prevents index usage because the IN loop is not compatible with index ordering in the old
* planner but causes an IN-UNION to be created in the new planner.
*/
@DualPlannerTest
void testInQueryOrMultipleIndexes() throws Exception {
complexQuerySetup(NO_HOOK);
planner.setConfiguration(InAsOrUnionMode.AS_UNION.configure(planner.getConfiguration().asBuilder()).build());
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.or(Query.field("str_value_indexed").equalsValue("odd"), Query.field("num_value_3_indexed").in(Arrays.asList(1, 3)))).build();
RecordQueryPlan plan = planner.plan(query);
if (planner instanceof RecordQueryPlanner) {
// Two ordinary equals single-column index scans would be compatible on the following primary key, but
// the IN loop inside one branch prevents that here. A regular filter would not.
assertMatchesExactly(plan, unorderedPrimaryKeyDistinctPlan(unorderedUnionPlan(indexPlan().where(indexName("MySimpleRecord$str_value_indexed")).and(scanComparisons(range("[[odd],[odd]]"))), inValuesJoinPlan(indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed")).and(scanComparisons(range("[EQUALS $__in_num_value_3_indexed__0]")))).where(inValuesList(equalsObject(Arrays.asList(1, 3)))))));
assertEquals(-1310248168, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(1826025907, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1395411845, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertMatchesExactly(plan, fetchFromPartialRecordPlan(unionPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$str_value_indexed")))), inUnionPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed")).and(scanComparisons(equalities(exactly(anyParameterComparison()))))))).where(inUnionComparisonKey(primaryKey("MySimpleRecord"))).and(inUnionValuesSources(exactly(inUnionInValues(equalsObject(ImmutableList.of(1, 3)))))))));
assertEquals(2086306995, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(527952105, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(626043938, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
}
Set<Long> dupes = new HashSet<>();
assertEquals(50 + 10 + 10, querySimpleRecordStore(NO_HOOK, plan, EvaluationContext::empty, record -> {
assertTrue(dupes.add(record.getRecNo()), "should not have duplicated records");
assertTrue(record.getStrValueIndexed().equals("odd") || record.getNumValue3Indexed() == 1 || record.getNumValue3Indexed() == 3);
}, context -> TestHelpers.assertDiscardedAtMost(20, context)));
}
use of com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan in project fdb-record-layer by FoundationDB.
the class FDBMultiFieldIndexSelectionTest method testComplexQuery3.
/**
* Verify that a complex query with an appropriate multi-field index uses the index.
*/
@DualPlannerTest
void testComplexQuery3() throws Exception {
// new Index("multi_index", "str_value_indexed", "num_value_2", "num_value_3_indexed")
RecordMetaDataHook hook = complexQuerySetupHook();
complexQuerySetup(hook);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.and(Query.field("str_value_indexed").equalsValue("even"), Query.field("num_value_2").equalsValue(0), Query.field("num_value_3_indexed").greaterThanOrEquals(2), Query.field("num_value_3_indexed").lessThanOrEquals(3))).build();
// Index(multi_index [[even, 0, 2],[even, 0, 3]])
RecordQueryPlan plan = planner.plan(query);
assertThat(plan, indexScan(allOf(indexName("multi_index"), bounds(hasTupleString("[[even, 0, 2],[even, 0, 3]]")))));
assertEquals(2137890746, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-64740525, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-868327560, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, hook);
int i = 0;
try (RecordCursorIterator<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan).asIterator()) {
while (cursor.hasNext()) {
FDBQueriedRecord<Message> rec = cursor.next();
TestRecords1Proto.MySimpleRecord.Builder myrec = TestRecords1Proto.MySimpleRecord.newBuilder();
myrec.mergeFrom(Objects.requireNonNull(rec).getRecord());
assertEquals("even", myrec.getStrValueIndexed());
assertEquals(0, (myrec.getNumValue2() % 3));
assertTrue((myrec.getNumValue3Indexed() % 5) >= 2);
assertTrue((myrec.getNumValue3Indexed() % 5) <= 3);
i++;
}
}
assertEquals(6, i);
TestHelpers.assertDiscardedNone(context);
}
}
use of com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan in project fdb-record-layer by FoundationDB.
the class FDBMultiFieldIndexSelectionTest method testComplexQuery2.
/**
* Verify that a complex query with an appropriate multi-field index uses the index.
*/
@DualPlannerTest
void testComplexQuery2() throws Exception {
RecordMetaDataHook hook = complexQuerySetupHook();
complexQuerySetup(hook);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.and(Query.field("str_value_indexed").equalsValue("even"), Query.field("num_value_3_indexed").equalsValue(3), Query.field("num_value_2").equalsValue(0))).build();
// Index(multi_index [[even, 0, 3],[even, 0, 3]])
RecordQueryPlan plan = planner.plan(query);
assertThat(plan, indexScan(allOf(indexName("multi_index"), bounds(hasTupleString("[[even, 0, 3],[even, 0, 3]]")))));
assertEquals(657537200, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(420201914, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1119403265, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, hook);
int i = 0;
try (RecordCursorIterator<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan).asIterator()) {
while (cursor.hasNext()) {
FDBQueriedRecord<Message> rec = cursor.next();
TestRecords1Proto.MySimpleRecord.Builder myrec = TestRecords1Proto.MySimpleRecord.newBuilder();
myrec.mergeFrom(Objects.requireNonNull(rec).getRecord());
assertEquals("even", myrec.getStrValueIndexed());
assertEquals(0, (myrec.getNumValue2() % 3));
assertEquals(3, (myrec.getNumValue3Indexed() % 5));
i++;
}
}
assertEquals(3, i);
TestHelpers.assertDiscardedNone(context);
}
}
Aggregations