Skip to content

Commit a9edd0f

Browse files
committed
Include planner phase specifc metrics in EXPLAIN result
1 parent cf9848b commit a9edd0f

File tree

3 files changed

+73
-17
lines changed

3 files changed

+73
-17
lines changed

fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/FDBRecordStoreQueryTestBase.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import com.apple.foundationdb.record.query.plan.RecordQueryPlanner;
5858
import com.apple.foundationdb.record.query.plan.cascades.CascadesPlanner;
5959
import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier;
60+
import com.apple.foundationdb.record.query.plan.cascades.PlannerPhase;
6061
import com.apple.foundationdb.record.query.plan.cascades.Reference;
6162
import com.apple.foundationdb.record.query.plan.cascades.debug.Debugger;
6263
import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher;
@@ -101,6 +102,7 @@
101102
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
102103
import static org.hamcrest.Matchers.instanceOf;
103104
import static org.hamcrest.Matchers.lessThanOrEqualTo;
105+
import static org.junit.jupiter.api.Assertions.assertEquals;
104106
import static org.junit.jupiter.api.Assertions.assertNotNull;
105107
import static org.junit.jupiter.api.Assertions.assertTrue;
106108
import static org.junit.jupiter.api.Assertions.fail;
@@ -664,7 +666,24 @@ protected RecordQueryPlan planGraph(@Nonnull Supplier<Reference> querySupplier,
664666
assertNotNull(statsMaps);
665667
final var eventClassStatsMap = statsMaps.getEventClassStatsMap();
666668
assertTrue(eventClassStatsMap.containsKey(Debugger.ExecutingTaskEvent.class));
667-
assertTrue(eventClassStatsMap.get(Debugger.ExecutingTaskEvent.class).getCount(Debugger.Location.BEGIN) > 0);
669+
670+
final var eventClassStatsMapForRewriting = statsMaps.getEventWithStateClassStatsMapByPlannerPhase(PlannerPhase.REWRITING);
671+
assertTrue(eventClassStatsMapForRewriting.isPresent());
672+
assertTrue(eventClassStatsMapForRewriting.get().containsKey(Debugger.ExecutingTaskEvent.class));
673+
assertTrue(eventClassStatsMapForRewriting.get().get(Debugger.ExecutingTaskEvent.class).getCount(Debugger.Location.BEGIN) > 0);
674+
675+
final var eventClassStatsMapForPlanning = statsMaps.getEventWithStateClassStatsMapByPlannerPhase(PlannerPhase.PLANNING);
676+
assertTrue(eventClassStatsMapForPlanning.isPresent());
677+
assertTrue(eventClassStatsMapForPlanning.get().containsKey(Debugger.ExecutingTaskEvent.class));
678+
679+
final var totalTasks = eventClassStatsMap.get(Debugger.ExecutingTaskEvent.class).getCount(Debugger.Location.BEGIN);
680+
final var rewritingTasks = eventClassStatsMapForRewriting.get().get(Debugger.ExecutingTaskEvent.class).getCount(Debugger.Location.BEGIN);
681+
final var planningTasks = eventClassStatsMapForPlanning.get().get(Debugger.ExecutingTaskEvent.class).getCount(Debugger.Location.BEGIN);
682+
683+
assertTrue(totalTasks > 0);
684+
assertTrue(rewritingTasks > 0);
685+
assertTrue(planningTasks > 0);
686+
assertEquals(rewritingTasks + planningTasks, totalTasks);
668687

669688
final var plan = planResult.getPlan();
670689
System.out.println("\n" + ExplainPlanVisitor.prettyExplain(plan) + "\n");
@@ -693,7 +712,7 @@ protected static RecordQueryPlan verifySerialization(@Nonnull final RecordQueryP
693712
final PlanSerializationContext deserializationContext = new PlanSerializationContext(new DefaultPlanSerializationRegistry(), PlanHashable.CURRENT_FOR_CONTINUATION);
694713
final RecordQueryPlan deserializedPlan =
695714
RecordQueryPlan.fromRecordQueryPlanProto(deserializationContext, parsedPlanProto);
696-
Assertions.assertEquals(plan.planHash(PlanHashable.CURRENT_FOR_CONTINUATION), deserializedPlan.planHash(PlanHashable.CURRENT_FOR_CONTINUATION));
715+
assertEquals(plan.planHash(PlanHashable.CURRENT_FOR_CONTINUATION), deserializedPlan.planHash(PlanHashable.CURRENT_FOR_CONTINUATION));
697716
Assertions.assertTrue(plan.structuralEquals(deserializedPlan));
698717
return deserializedPlan;
699718
}

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/QueryPlan.java

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import com.apple.foundationdb.record.query.plan.QueryPlanInfoKeys;
3434
import com.apple.foundationdb.record.query.plan.QueryPlanResult;
3535
import com.apple.foundationdb.record.query.plan.cascades.CascadesPlanner;
36+
import com.apple.foundationdb.record.query.plan.cascades.PlannerPhase;
3637
import com.apple.foundationdb.record.query.plan.cascades.Reference;
3738
import com.apple.foundationdb.record.query.plan.cascades.debug.Debugger;
3839
import com.apple.foundationdb.record.query.plan.cascades.debug.Stats;
@@ -88,6 +89,7 @@
8889
import java.sql.Struct;
8990
import java.util.ArrayList;
9091
import java.util.Collections;
92+
9193
import java.util.List;
9294
import java.util.Map;
9395
import java.util.Objects;
@@ -296,7 +298,11 @@ private RelationalResultSet executeExplain(@Nonnull ContinuationImpl parsedConti
296298
DataType.StructType.Field.from("TRANSFORM_YIELD_COUNT", DataType.Primitives.LONG.type(), 4),
297299
DataType.StructType.Field.from("INSERT_TIME_NS", DataType.Primitives.LONG.type(), 5),
298300
DataType.StructType.Field.from("INSERT_NEW_COUNT", DataType.Primitives.LONG.type(), 6),
299-
DataType.StructType.Field.from("INSERT_REUSED_COUNT", DataType.Primitives.LONG.type(), 7)),
301+
DataType.StructType.Field.from("INSERT_REUSED_COUNT", DataType.Primitives.LONG.type(), 7),
302+
DataType.StructType.Field.from("REWRITING_PHASE_TASK_COUNT", DataType.Primitives.LONG.type(), 8),
303+
DataType.StructType.Field.from("PLANNING_PHASE_TASK_COUNT", DataType.Primitives.LONG.type(), 9),
304+
DataType.StructType.Field.from("REWRITING_PHASE_TASKS_TOTAL_TIME_NS", DataType.Primitives.LONG.type(), 10),
305+
DataType.StructType.Field.from("PLANNING_PHASE_TASKS_TOTAL_TIME_NS", DataType.Primitives.LONG.type(), 11)),
300306
true);
301307
final var explainStructType = DataType.StructType.from(
302308
"EXPLAIN", List.of(
@@ -320,25 +326,35 @@ private RelationalResultSet executeExplain(@Nonnull ContinuationImpl parsedConti
320326
plannerMetrics = null;
321327
} else {
322328
final var plannerEventClassStatsMap = plannerStatsMaps.getEventClassStatsMap();
323-
final var executingTasksStats =
329+
330+
final var aggregateExecutingTasksStats =
324331
Optional.ofNullable(plannerEventClassStatsMap.get(Debugger.ExecutingTaskEvent.class));
325-
final var transformRuleCallStats =
332+
final var aggregateTransformRuleCallStats =
326333
Optional.ofNullable(plannerEventClassStatsMap.get(Debugger.TransformRuleCallEvent.class));
327-
final var insertIntoMemoStats =
334+
final var aggregateInsertIntoMemoStats =
328335
Optional.ofNullable(plannerEventClassStatsMap.get(Debugger.InsertIntoMemoEvent.class));
329336

337+
final var executingTasksStatsForRewritingPhase =
338+
plannerStatsMaps.getEventWithStateClassStatsMapByPlannerPhase(PlannerPhase.REWRITING)
339+
.map(m -> m.get(Debugger.ExecutingTaskEvent.class));
340+
final var executingTasksStatsForPlanningPhase =
341+
plannerStatsMaps.getEventWithStateClassStatsMapByPlannerPhase(PlannerPhase.PLANNING)
342+
.map(m -> m.get(Debugger.ExecutingTaskEvent.class));
343+
330344
plannerMetrics =
331345
new ImmutableRowStruct(new ArrayRow(
332-
executingTasksStats.map(s -> s.getCount(Debugger.Location.BEGIN)).orElse(0L),
333-
executingTasksStats.map(Stats::getTotalTimeInNs).orElse(0L),
334-
transformRuleCallStats.map(s -> s.getCount(Debugger.Location.BEGIN)).orElse(0L),
335-
transformRuleCallStats.map(Stats::getOwnTimeInNs).orElse(0L),
336-
transformRuleCallStats.map(s -> s.getCount(Debugger.Location.YIELD)).orElse(0L),
337-
insertIntoMemoStats.map(Stats::getOwnTimeInNs).orElse(0L),
338-
insertIntoMemoStats.map(s -> s.getCount(Debugger.Location.NEW)).orElse(0L),
339-
insertIntoMemoStats.map(s -> s.getCount(Debugger.Location.REUSED)).orElse(0L),
340-
parsedContinuation.getVersion(),
341-
parsedContinuation.getCompiledStatement() == null ? null : parsedContinuation.getCompiledStatement().getPlanSerializationMode()
346+
aggregateExecutingTasksStats.map(s -> s.getCount(Debugger.Location.BEGIN)).orElse(0L),
347+
aggregateExecutingTasksStats.map(Stats::getTotalTimeInNs).orElse(0L),
348+
aggregateTransformRuleCallStats.map(s -> s.getCount(Debugger.Location.BEGIN)).orElse(0L),
349+
aggregateTransformRuleCallStats.map(Stats::getOwnTimeInNs).orElse(0L),
350+
aggregateTransformRuleCallStats.map(s -> s.getCount(Debugger.Location.YIELD)).orElse(0L),
351+
aggregateInsertIntoMemoStats.map(Stats::getOwnTimeInNs).orElse(0L),
352+
aggregateInsertIntoMemoStats.map(s -> s.getCount(Debugger.Location.NEW)).orElse(0L),
353+
aggregateInsertIntoMemoStats.map(s -> s.getCount(Debugger.Location.REUSED)).orElse(0L),
354+
executingTasksStatsForRewritingPhase.map(s -> s.getCount(Debugger.Location.BEGIN)).orElse(0L),
355+
executingTasksStatsForPlanningPhase.map(s -> s.getCount(Debugger.Location.BEGIN)).orElse(0L),
356+
executingTasksStatsForRewritingPhase.map(Stats::getTotalTimeInNs).orElse(0L),
357+
executingTasksStatsForPlanningPhase.map(Stats::getTotalTimeInNs).orElse(0L)
342358
), RelationalStructMetaData.of(plannerMetricsStructType));
343359
}
344360

fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/ExplainTests.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import java.net.URI;
4141
import java.sql.SQLException;
4242
import java.sql.Types;
43+
import java.util.Collections;
4344
import java.util.List;
4445

4546
public class ExplainTests {
@@ -71,6 +72,21 @@ void explainResultSetMetadataTest() throws Exception {
7172
final var expectedTypes = List.of(Types.VARCHAR, Types.INTEGER, Types.VARCHAR, Types.VARCHAR, Types.STRUCT, Types.STRUCT);
7273
final var expectedContLabels = List.of("EXECUTION_STATE", "VERSION", "PLAN_HASH_MODE");
7374
final var expectedContTypes = List.of(Types.BINARY, Types.INTEGER, Types.VARCHAR);
75+
final var expectedPlannerMetricsLabels = List.of(
76+
"TASK_COUNT",
77+
"TASK_TOTAL_TIME_NS",
78+
"TRANSFORM_COUNT",
79+
"TRANSFORM_TIME_NS",
80+
"TRANSFORM_YIELD_COUNT",
81+
"INSERT_TIME_NS",
82+
"INSERT_NEW_COUNT",
83+
"INSERT_REUSED_COUNT",
84+
"REWRITING_PHASE_TASK_COUNT",
85+
"PLANNING_PHASE_TASK_COUNT",
86+
"REWRITING_PHASE_TASKS_TOTAL_TIME_NS",
87+
"PLANNING_PHASE_TASKS_TOTAL_TIME_NS"
88+
);
89+
final var expectedPlannerMetricsTypes = Collections.nCopies(expectedPlannerMetricsLabels.size(), Types.BIGINT);
7490
try (var ddl = Ddl.builder().database(URI.create("/TEST/QT")).relationalExtension(relationalExtension).schemaTemplate(schemaTemplate).build()) {
7591
executeInsert(ddl);
7692
try (RelationalPreparedStatement ps = ddl.setSchemaAndGetConnection().prepareStatement("EXPLAIN SELECT * FROM RestaurantComplexRecord")) {
@@ -87,7 +103,12 @@ void explainResultSetMetadataTest() throws Exception {
87103
org.junit.jupiter.api.Assertions.assertEquals(expectedContLabels.get(i), actualContinuationMetadata.getColumnLabel(i + 1));
88104
org.junit.jupiter.api.Assertions.assertEquals(expectedContTypes.get(i), actualContinuationMetadata.getColumnType(i + 1));
89105
}
90-
106+
final var actualPlannerMetricsMetadata = actualMetadata.getStructMetaData(6);
107+
org.junit.jupiter.api.Assertions.assertEquals(expectedPlannerMetricsLabels.size(), actualPlannerMetricsMetadata.getColumnCount());
108+
for (int i = 0; i < expectedPlannerMetricsLabels.size(); i++) {
109+
org.junit.jupiter.api.Assertions.assertEquals(expectedPlannerMetricsLabels.get(i), actualPlannerMetricsMetadata.getColumnLabel(i + 1));
110+
org.junit.jupiter.api.Assertions.assertEquals(expectedPlannerMetricsTypes.get(i), actualPlannerMetricsMetadata.getColumnType(i + 1));
111+
}
91112
}
92113
}
93114
}

0 commit comments

Comments
 (0)