This is an automated email from the ASF dual-hosted git repository. stoty pushed a commit to branch 4.x in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/4.x by this push: new e281ec6 PHOENIX-5728 : ExplainPlan with plan as attributes object e281ec6 is described below commit e281ec67e49b1dc8b924a7faa5f6fc8529bce1b3 Author: Viraj Jasani <vjas...@apache.org> AuthorDate: Mon Nov 30 23:02:12 2020 +0530 PHOENIX-5728 : ExplainPlan with plan as attributes object --- .../apache/phoenix/iterate/MockResultIterator.java | 7 + .../phoenix/schema/stats/BaseStatsCollectorIT.java | 129 +++-- .../org/apache/phoenix/compile/DeleteCompiler.java | 25 +- .../org/apache/phoenix/compile/ExplainPlan.java | 19 +- .../phoenix/compile/ExplainPlanAttributes.java | 598 +++++++++++++++++++++ .../apache/phoenix/compile/GroupByCompiler.java | 51 +- .../apache/phoenix/compile/ListJarsQueryPlan.java | 7 + .../compile/MutatingParallelIteratorFactory.java | 7 + .../org/apache/phoenix/compile/TraceQueryPlan.java | 7 + .../org/apache/phoenix/compile/UpsertCompiler.java | 28 +- .../org/apache/phoenix/execute/BaseQueryPlan.java | 18 +- .../phoenix/execute/ClientAggregatePlan.java | 34 +- .../org/apache/phoenix/execute/ClientScanPlan.java | 23 +- .../org/apache/phoenix/execute/CorrelatePlan.java | 37 +- .../org/apache/phoenix/execute/HashJoinPlan.java | 1 + .../execute/LiteralResultIterationPlan.java | 9 +- .../apache/phoenix/execute/SortMergeJoinPlan.java | 44 +- .../phoenix/execute/TupleProjectionPlan.java | 14 +- .../java/org/apache/phoenix/execute/UnionPlan.java | 12 +- .../apache/phoenix/execute/UnnestArrayPlan.java | 13 +- .../BaseGroupedAggregatingResultIterator.java | 7 + .../apache/phoenix/iterate/BaseResultIterator.java | 7 + .../phoenix/iterate/BaseResultIterators.java | 67 ++- .../phoenix/iterate/ChunkedResultIterator.java | 14 + .../ClientHashAggregatingResultIterator.java | 8 + .../phoenix/iterate/ConcatResultIterator.java | 10 + .../phoenix/iterate/CursorResultIterator.java | 10 + .../phoenix/iterate/DelegateResultIterator.java | 8 + .../iterate/DistinctAggregatingResultIterator.java | 11 + .../org/apache/phoenix/iterate/ExplainTable.java | 91 +++- .../iterate/FilterAggregatingResultIterator.java | 20 +- .../phoenix/iterate/FilterResultIterator.java | 20 +- .../phoenix/iterate/LimitingResultIterator.java | 22 +- .../phoenix/iterate/LookAheadResultIterator.java | 8 + .../MaterializedComparableResultIterator.java | 8 + .../iterate/MaterializedResultIterator.java | 7 + .../iterate/MergeSortRowKeyResultIterator.java | 20 +- .../iterate/MergeSortTopNResultIterator.java | 30 +- .../phoenix/iterate/OffsetResultIterator.java | 10 + .../phoenix/iterate/OrderedResultIterator.java | 20 + .../phoenix/iterate/PeekingResultIterator.java | 7 + .../org/apache/phoenix/iterate/ResultIterator.java | 24 + .../apache/phoenix/iterate/ResultIterators.java | 20 + .../phoenix/iterate/RoundRobinResultIterator.java | 16 + .../RowKeyOrderedAggregateResultIterator.java | 10 + .../phoenix/iterate/ScanningResultIterator.java | 7 + .../phoenix/iterate/SequenceResultIterator.java | 22 +- .../apache/phoenix/iterate/SerialIterators.java | 7 + .../phoenix/iterate/SpoolingResultIterator.java | 17 + .../phoenix/iterate/TableResultIterator.java | 8 + .../iterate/TableSnapshotResultIterator.java | 15 +- .../phoenix/iterate/UnionResultIterators.java | 30 +- .../phoenix/iterate/ConcatResultIteratorTest.java | 8 + .../iterate/MaterializedResultIterators.java | 7 + .../iterate/MergeSortResultIteratorTest.java | 17 + 55 files changed, 1552 insertions(+), 144 deletions(-) diff --git a/phoenix-core/src/it/java/org/apache/phoenix/iterate/MockResultIterator.java b/phoenix-core/src/it/java/org/apache/phoenix/iterate/MockResultIterator.java index e842317..5b5b643 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/iterate/MockResultIterator.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/iterate/MockResultIterator.java @@ -28,6 +28,8 @@ import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.util.Bytes; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.execute.TupleProjector; import org.apache.phoenix.schema.PTable; import org.apache.phoenix.schema.tuple.ResultTuple; @@ -56,6 +58,11 @@ public class MockResultIterator implements PeekingResultIterator { public void explain(List<String> planSteps) {} @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } + + @Override public void close() throws SQLException {} @Override diff --git a/phoenix-core/src/it/java/org/apache/phoenix/schema/stats/BaseStatsCollectorIT.java b/phoenix-core/src/it/java/org/apache/phoenix/schema/stats/BaseStatsCollectorIT.java index 39c68e5..97cfa8f 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/schema/stats/BaseStatsCollectorIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/schema/stats/BaseStatsCollectorIT.java @@ -26,6 +26,7 @@ import static org.apache.phoenix.util.TestUtil.getAllSplits; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -46,6 +47,9 @@ import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HRegionLocation; import org.apache.hadoop.hbase.TableName; +import org.apache.phoenix.compile.ExplainPlan; +import org.apache.phoenix.compile.ExplainPlanAttributes; +import org.apache.phoenix.jdbc.PhoenixPreparedStatement; import org.apache.hadoop.hbase.client.HBaseAdmin; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; @@ -252,12 +256,16 @@ public abstract class BaseStatsCollectorIT extends BaseUniqueNamesOwnClusterIT { conn.createStatement().execute( "CREATE TABLE " + fullTableName +" ( k CHAR(1) PRIMARY KEY )" + tableDDLOptions); collectStatistics(conn, fullTableName); - ResultSet rs = conn.createStatement().executeQuery("EXPLAIN SELECT * FROM " + fullTableName); - String explainPlan = QueryUtil.getExplainPlan(rs); - assertEquals( - "CLIENT 1-CHUNK 0 ROWS 20 BYTES PARALLEL 1-WAY FULL SCAN OVER " + physicalTableName + "\n" + - " SERVER FILTER BY FIRST KEY ONLY", - explainPlan); + ExplainPlan plan = conn.prepareStatement("SELECT * FROM " + fullTableName) + .unwrap(PhoenixPreparedStatement.class).optimizeQuery().getExplainPlan(); + ExplainPlanAttributes planAttributes = plan.getPlanStepsAsAttributes(); + assertEquals(1, (int) planAttributes.getSplitsChunk()); + assertEquals(0, (long) planAttributes.getEstimatedRows()); + assertEquals(20, (long) planAttributes.getEstimatedSizeInBytes()); + assertEquals("PARALLEL 1-WAY", planAttributes.getIteratorTypeAndScanSize()); + assertEquals("FULL SCAN ", planAttributes.getExplainScanType()); + assertEquals(physicalTableName, planAttributes.getTableName()); + assertEquals("SERVER FILTER BY FIRST KEY ONLY", planAttributes.getServerWhereFilter()); conn.close(); } @@ -270,30 +278,56 @@ public abstract class BaseStatsCollectorIT extends BaseUniqueNamesOwnClusterIT { conn.createStatement().execute("UPSERT INTO " + fullTableName + "(k,v1) VALUES('a','123456789')"); collectStatistics(conn, fullTableName); - ResultSet rs; - String explainPlan; - rs = conn.createStatement().executeQuery("EXPLAIN SELECT v2 FROM " + fullTableName + " WHERE v2='foo'"); - explainPlan = QueryUtil.getExplainPlan(rs); - // if we are using the ONE_CELL_PER_COLUMN_FAMILY storage scheme, we will have the single kv even though there are no values for col family v2 - String stats = columnEncoded && !mutable ? "4-CHUNK 1 ROWS 38 BYTES" : "3-CHUNK 0 ROWS 20 BYTES"; - assertEquals( - "CLIENT " + stats + " PARALLEL 3-WAY FULL SCAN OVER " + physicalTableName + "\n" + - " SERVER FILTER BY B.V2 = 'foo'\n" + - "CLIENT MERGE SORT", - explainPlan); - rs = conn.createStatement().executeQuery("EXPLAIN SELECT * FROM " + fullTableName); - explainPlan = QueryUtil.getExplainPlan(rs); - assertEquals( - "CLIENT 4-CHUNK 1 ROWS " + (columnEncoded ? "28" : TransactionFactory.Provider.OMID.name().equals(transactionProvider) ? "38" : "34") + " BYTES PARALLEL 3-WAY FULL SCAN OVER " + physicalTableName + "\n" + - "CLIENT MERGE SORT", - explainPlan); - rs = conn.createStatement().executeQuery("EXPLAIN SELECT * FROM " + fullTableName + " WHERE k = 'a'"); - explainPlan = QueryUtil.getExplainPlan(rs); - assertEquals( - "CLIENT 1-CHUNK 1 ROWS " + (columnEncoded ? "204" : "202") + " BYTES PARALLEL 1-WAY POINT LOOKUP ON 1 KEY OVER " + physicalTableName + "\n" + - "CLIENT MERGE SORT", - explainPlan); - + // if we are using the ONE_CELL_PER_COLUMN_FAMILY storage scheme, we will have the single kv even though there are no values for col family v2 + + ExplainPlan plan = conn.prepareStatement( + "SELECT v2 FROM " + fullTableName + " WHERE v2='foo'") + .unwrap(PhoenixPreparedStatement.class).optimizeQuery().getExplainPlan(); + ExplainPlanAttributes planAttributes = plan.getPlanStepsAsAttributes(); + assertEquals(columnEncoded && !mutable ? 4 : 3, + (int) planAttributes.getSplitsChunk()); + assertEquals(columnEncoded && !mutable ? 1 : 0, + (long) planAttributes.getEstimatedRows()); + assertEquals(columnEncoded && !mutable ? 38 : 20, + (long) planAttributes.getEstimatedSizeInBytes()); + assertEquals("PARALLEL 3-WAY", planAttributes.getIteratorTypeAndScanSize()); + assertEquals("FULL SCAN ", planAttributes.getExplainScanType()); + assertEquals(physicalTableName, planAttributes.getTableName()); + assertEquals("SERVER FILTER BY B.V2 = 'foo'", + planAttributes.getServerWhereFilter()); + assertEquals("CLIENT MERGE SORT", planAttributes.getClientSortAlgo()); + + long estimatedSizeInBytes = columnEncoded ? 28 + : TransactionFactory.Provider.OMID.name().equals(transactionProvider) + ? 38 : 34; + plan = conn.prepareStatement( + "SELECT * FROM " + fullTableName) + .unwrap(PhoenixPreparedStatement.class).optimizeQuery().getExplainPlan(); + planAttributes = plan.getPlanStepsAsAttributes(); + assertEquals(4, (int) planAttributes.getSplitsChunk()); + assertEquals(1, (long) planAttributes.getEstimatedRows()); + assertEquals(estimatedSizeInBytes, + (long) planAttributes.getEstimatedSizeInBytes()); + assertEquals("PARALLEL 3-WAY", planAttributes.getIteratorTypeAndScanSize()); + assertEquals("FULL SCAN ", planAttributes.getExplainScanType()); + assertEquals(physicalTableName, planAttributes.getTableName()); + assertNull(planAttributes.getServerWhereFilter()); + assertEquals("CLIENT MERGE SORT", planAttributes.getClientSortAlgo()); + + plan = conn.prepareStatement( + "SELECT * FROM " + fullTableName + " WHERE k = 'a'") + .unwrap(PhoenixPreparedStatement.class).optimizeQuery().getExplainPlan(); + planAttributes = plan.getPlanStepsAsAttributes(); + assertEquals(1, (int) planAttributes.getSplitsChunk()); + assertEquals(1, (long) planAttributes.getEstimatedRows()); + assertEquals(columnEncoded ? 204 : 202, + (long) planAttributes.getEstimatedSizeInBytes()); + assertEquals("PARALLEL 1-WAY", planAttributes.getIteratorTypeAndScanSize()); + assertEquals("POINT LOOKUP ON 1 KEY ", planAttributes.getExplainScanType()); + assertEquals(physicalTableName, planAttributes.getTableName()); + assertNull(planAttributes.getServerWhereFilter()); + assertEquals("CLIENT MERGE SORT", planAttributes.getClientSortAlgo()); + conn.close(); } @@ -569,9 +603,23 @@ public abstract class BaseStatsCollectorIT extends BaseUniqueNamesOwnClusterIT { collectStatistics(conn, fullTableName); List<KeyRange> keyRanges = getAllSplits(conn, fullTableName); assertEquals(26, keyRanges.size()); - rs = conn.createStatement().executeQuery("EXPLAIN SELECT * FROM " + fullTableName); - assertEquals("CLIENT 26-CHUNK 25 ROWS " + (columnEncoded ? ( mutable ? "12530" : "13902" ) : (TransactionFactory.Provider.OMID.name().equals(transactionProvider)) ? "25044" : "12420") + " BYTES PARALLEL 1-WAY FULL SCAN OVER " + physicalTableName, - QueryUtil.getExplainPlan(rs)); + + long sizeInBytes = columnEncoded ? (mutable ? 12530 : 13902) + : (TransactionFactory.Provider.OMID.name().equals(transactionProvider)) + ? 25044 : 12420; + + ExplainPlan plan = conn.prepareStatement( + "SELECT * FROM " + fullTableName) + .unwrap(PhoenixPreparedStatement.class).optimizeQuery().getExplainPlan(); + ExplainPlanAttributes planAttributes = plan.getPlanStepsAsAttributes(); + assertEquals(26, (int) planAttributes.getSplitsChunk()); + assertEquals(25, (long) planAttributes.getEstimatedRows()); + assertEquals(sizeInBytes, + (long) planAttributes.getEstimatedSizeInBytes()); + assertEquals("PARALLEL 1-WAY", + planAttributes.getIteratorTypeAndScanSize()); + assertEquals("FULL SCAN ", planAttributes.getExplainScanType()); + assertEquals(physicalTableName, planAttributes.getTableName()); ConnectionQueryServices services = conn.unwrap(PhoenixConnection.class).getQueryServices(); List<HRegionLocation> regions = services.getAllTableRegions(Bytes.toBytes(physicalTableName)); @@ -625,9 +673,18 @@ public abstract class BaseStatsCollectorIT extends BaseUniqueNamesOwnClusterIT { assertTrue(rs.next()); assertEquals(0, rs.getLong(1)); assertFalse(rs.next()); - rs = conn.createStatement().executeQuery("EXPLAIN SELECT * FROM " + fullTableName); - assertEquals("CLIENT 1-CHUNK PARALLEL 1-WAY FULL SCAN OVER " + physicalTableName, - QueryUtil.getExplainPlan(rs)); + + plan = conn.prepareStatement( + "SELECT * FROM " + fullTableName) + .unwrap(PhoenixPreparedStatement.class).optimizeQuery().getExplainPlan(); + planAttributes = plan.getPlanStepsAsAttributes(); + assertEquals(1, (int) planAttributes.getSplitsChunk()); + assertNull(planAttributes.getEstimatedRows()); + assertNull(planAttributes.getEstimatedSizeInBytes()); + assertEquals("PARALLEL 1-WAY", + planAttributes.getIteratorTypeAndScanSize()); + assertEquals("FULL SCAN ", planAttributes.getExplainScanType()); + assertEquals(physicalTableName, planAttributes.getTableName()); } @Test diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/DeleteCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/DeleteCompiler.java index 8b43c8c..ebba909 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/DeleteCompiler.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/DeleteCompiler.java @@ -36,6 +36,8 @@ import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.util.Pair; import org.apache.phoenix.cache.ServerCacheClient; import org.apache.phoenix.cache.ServerCacheClient.ServerCache; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.GroupByCompiler.GroupBy; import org.apache.phoenix.compile.OrderByCompiler.OrderBy; import org.apache.phoenix.coprocessor.BaseScannerRegionObserver; @@ -823,11 +825,18 @@ public class DeleteCompiler { @Override public ExplainPlan getExplainPlan() throws SQLException { - List<String> queryPlanSteps = aggPlan.getExplainPlan().getPlanSteps(); - List<String> planSteps = Lists.newArrayListWithExpectedSize(queryPlanSteps.size()+1); + ExplainPlan explainPlan = aggPlan.getExplainPlan(); + List<String> queryPlanSteps = explainPlan.getPlanSteps(); + ExplainPlanAttributes explainPlanAttributes = + explainPlan.getPlanStepsAsAttributes(); + List<String> planSteps = + Lists.newArrayListWithExpectedSize(queryPlanSteps.size() + 1); + ExplainPlanAttributesBuilder newBuilder = + new ExplainPlanAttributesBuilder(explainPlanAttributes); + newBuilder.setAbstractExplainPlan("DELETE ROWS SERVER SELECT"); planSteps.add("DELETE ROWS SERVER SELECT"); planSteps.addAll(queryPlanSteps); - return new ExplainPlan(planSteps); + return new ExplainPlan(planSteps, newBuilder.build()); } @Override @@ -945,11 +954,17 @@ public class DeleteCompiler { @Override public ExplainPlan getExplainPlan() throws SQLException { - List<String> queryPlanSteps = bestPlan.getExplainPlan().getPlanSteps(); + ExplainPlan explainPlan = bestPlan.getExplainPlan(); + List<String> queryPlanSteps = explainPlan.getPlanSteps(); + ExplainPlanAttributes explainPlanAttributes = + explainPlan.getPlanStepsAsAttributes(); List<String> planSteps = Lists.newArrayListWithExpectedSize(queryPlanSteps.size()+1); + ExplainPlanAttributesBuilder newBuilder = + new ExplainPlanAttributesBuilder(explainPlanAttributes); + newBuilder.setAbstractExplainPlan("DELETE ROWS CLIENT SELECT"); planSteps.add("DELETE ROWS CLIENT SELECT"); planSteps.addAll(queryPlanSteps); - return new ExplainPlan(planSteps); + return new ExplainPlan(planSteps, newBuilder.build()); } @Override diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/ExplainPlan.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExplainPlan.java index ef34daa..a180b6f 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/ExplainPlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExplainPlan.java @@ -26,15 +26,28 @@ public class ExplainPlan { public static final ExplainPlan EMPTY_PLAN = new ExplainPlan(Collections.<String>emptyList()); private final List<String> planSteps; - + private final ExplainPlanAttributes planStepsAsAttributes; + public ExplainPlan(List<String> planSteps) { this.planSteps = ImmutableList.copyOf(planSteps); + this.planStepsAsAttributes = + ExplainPlanAttributes.getDefaultExplainPlan(); + } + + public ExplainPlan(List<String> planSteps, + ExplainPlanAttributes planStepsAsAttributes) { + this.planSteps = planSteps; + this.planStepsAsAttributes = planStepsAsAttributes; } - + public List<String> getPlanSteps() { return planSteps; } - + + public ExplainPlanAttributes getPlanStepsAsAttributes() { + return planStepsAsAttributes; + } + @Override public String toString() { StringBuilder buf = new StringBuilder(); diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/ExplainPlanAttributes.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExplainPlanAttributes.java new file mode 100644 index 0000000..855ce96 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExplainPlanAttributes.java @@ -0,0 +1,598 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.phoenix.compile; + +import org.apache.hadoop.hbase.client.Consistency; +import org.apache.phoenix.parse.HintNode; +import org.apache.phoenix.parse.HintNode.Hint; + +/** + * ExplainPlan attributes that contain individual attributes of ExplainPlan + * that we can assert against. This also makes attribute retrieval easier + * as an API rather than retrieving list of Strings containing entire plan. + */ +public class ExplainPlanAttributes { + + private final String abstractExplainPlan; + private final Integer splitsChunk; + private final Long estimatedRows; + private final Long estimatedSizeInBytes; + private final String iteratorTypeAndScanSize; + private final Double samplingRate; + private final boolean useRoundRobinIterator; + private final String hexStringRVCOffset; + private final Consistency consistency; + private final Hint hint; + private final String serverSortedBy; + private final String explainScanType; + private final String tableName; + private final String keyRanges; + private final Long scanTimeRangeMin; + private final Long scanTimeRangeMax; + private final String serverWhereFilter; + private final String serverDistinctFilter; + private final Integer serverOffset; + private final Long serverRowLimit; + private final boolean serverArrayElementProjection; + private final String serverAggregate; + private final String clientFilterBy; + private final String clientAggregate; + private final String clientSortedBy; + private final String clientAfterAggregate; + private final String clientDistinctFilter; + private final Integer clientOffset; + private final Integer clientRowLimit; + private final Integer clientSequenceCount; + private final String clientCursorName; + private final String clientSortAlgo; + // This object represents PlanAttributes object for rhs query + // to be used only by Join queries. In case of Join query, lhs plan is + // represented by 'this' object and rhs plan is represented by + // 'rhsJoinQueryExplainPlan' object (which in turn should + // have null rhsJoinQueryExplainPlan) + // For non-Join queries related Plans, rhsJoinQueryExplainPlan will always + // be null + private final ExplainPlanAttributes rhsJoinQueryExplainPlan; + + private static final ExplainPlanAttributes EXPLAIN_PLAN_INSTANCE = + new ExplainPlanAttributes(); + + private ExplainPlanAttributes() { + this.abstractExplainPlan = null; + this.splitsChunk = null; + this.estimatedRows = null; + this.estimatedSizeInBytes = null; + this.iteratorTypeAndScanSize = null; + this.samplingRate = null; + this.useRoundRobinIterator = false; + this.hexStringRVCOffset = null; + this.consistency = null; + this.hint = null; + this.serverSortedBy = null; + this.explainScanType = null; + this.tableName = null; + this.keyRanges = null; + this.scanTimeRangeMin = null; + this.scanTimeRangeMax = null; + this.serverWhereFilter = null; + this.serverDistinctFilter = null; + this.serverOffset = null; + this.serverRowLimit = null; + this.serverArrayElementProjection = false; + this.serverAggregate = null; + this.clientFilterBy = null; + this.clientAggregate = null; + this.clientSortedBy = null; + this.clientAfterAggregate = null; + this.clientDistinctFilter = null; + this.clientOffset = null; + this.clientRowLimit = null; + this.clientSequenceCount = null; + this.clientCursorName = null; + this.clientSortAlgo = null; + this.rhsJoinQueryExplainPlan = null; + } + + public ExplainPlanAttributes(String abstractExplainPlan, + Integer splitsChunk, Long estimatedRows, Long estimatedSizeInBytes, + String iteratorTypeAndScanSize, Double samplingRate, + boolean useRoundRobinIterator, + String hexStringRVCOffset, Consistency consistency, + Hint hint, String serverSortedBy, String explainScanType, + String tableName, String keyRanges, Long scanTimeRangeMin, + Long scanTimeRangeMax, String serverWhereFilter, + String serverDistinctFilter, + Integer serverOffset, Long serverRowLimit, + boolean serverArrayElementProjection, String serverAggregate, + String clientFilterBy, String clientAggregate, + String clientSortedBy, + String clientAfterAggregate, String clientDistinctFilter, + Integer clientOffset, Integer clientRowLimit, + Integer clientSequenceCount, String clientCursorName, + String clientSortAlgo, + ExplainPlanAttributes rhsJoinQueryExplainPlan) { + this.abstractExplainPlan = abstractExplainPlan; + this.splitsChunk = splitsChunk; + this.estimatedRows = estimatedRows; + this.estimatedSizeInBytes = estimatedSizeInBytes; + this.iteratorTypeAndScanSize = iteratorTypeAndScanSize; + this.samplingRate = samplingRate; + this.useRoundRobinIterator = useRoundRobinIterator; + this.hexStringRVCOffset = hexStringRVCOffset; + this.consistency = consistency; + this.hint = hint; + this.serverSortedBy = serverSortedBy; + this.explainScanType = explainScanType; + this.tableName = tableName; + this.keyRanges = keyRanges; + this.scanTimeRangeMin = scanTimeRangeMin; + this.scanTimeRangeMax = scanTimeRangeMax; + this.serverWhereFilter = serverWhereFilter; + this.serverDistinctFilter = serverDistinctFilter; + this.serverOffset = serverOffset; + this.serverRowLimit = serverRowLimit; + this.serverArrayElementProjection = serverArrayElementProjection; + this.serverAggregate = serverAggregate; + this.clientFilterBy = clientFilterBy; + this.clientAggregate = clientAggregate; + this.clientSortedBy = clientSortedBy; + this.clientAfterAggregate = clientAfterAggregate; + this.clientDistinctFilter = clientDistinctFilter; + this.clientOffset = clientOffset; + this.clientRowLimit = clientRowLimit; + this.clientSequenceCount = clientSequenceCount; + this.clientCursorName = clientCursorName; + this.clientSortAlgo = clientSortAlgo; + this.rhsJoinQueryExplainPlan = rhsJoinQueryExplainPlan; + } + + public String getAbstractExplainPlan() { + return abstractExplainPlan; + } + + public Integer getSplitsChunk() { + return splitsChunk; + } + + public Long getEstimatedRows() { + return estimatedRows; + } + + public Long getEstimatedSizeInBytes() { + return estimatedSizeInBytes; + } + + public String getIteratorTypeAndScanSize() { + return iteratorTypeAndScanSize; + } + + public Double getSamplingRate() { + return samplingRate; + } + + public boolean isUseRoundRobinIterator() { + return useRoundRobinIterator; + } + + public String getHexStringRVCOffset() { + return hexStringRVCOffset; + } + + public Consistency getConsistency() { + return consistency; + } + + public Hint getHint() { + return hint; + } + + public String getServerSortedBy() { + return serverSortedBy; + } + + public String getExplainScanType() { + return explainScanType; + } + + public String getTableName() { + return tableName; + } + + public String getKeyRanges() { + return keyRanges; + } + + public Long getScanTimeRangeMin() { + return scanTimeRangeMin; + } + + public Long getScanTimeRangeMax() { + return scanTimeRangeMax; + } + + public String getServerWhereFilter() { + return serverWhereFilter; + } + + public String getServerDistinctFilter() { + return serverDistinctFilter; + } + + public Integer getServerOffset() { + return serverOffset; + } + + public Long getServerRowLimit() { + return serverRowLimit; + } + + public boolean isServerArrayElementProjection() { + return serverArrayElementProjection; + } + + public String getServerAggregate() { + return serverAggregate; + } + + public String getClientFilterBy() { + return clientFilterBy; + } + + public String getClientAggregate() { + return clientAggregate; + } + + public String getClientSortedBy() { + return clientSortedBy; + } + + public String getClientAfterAggregate() { + return clientAfterAggregate; + } + + public String getClientDistinctFilter() { + return clientDistinctFilter; + } + + public Integer getClientOffset() { + return clientOffset; + } + + public Integer getClientRowLimit() { + return clientRowLimit; + } + + public Integer getClientSequenceCount() { + return clientSequenceCount; + } + + public String getClientCursorName() { + return clientCursorName; + } + + public String getClientSortAlgo() { + return clientSortAlgo; + } + + public ExplainPlanAttributes getRhsJoinQueryExplainPlan() { + return rhsJoinQueryExplainPlan; + } + + public static ExplainPlanAttributes getDefaultExplainPlan() { + return EXPLAIN_PLAN_INSTANCE; + } + + public static class ExplainPlanAttributesBuilder { + private String abstractExplainPlan; + private Integer splitsChunk; + private Long estimatedRows; + private Long estimatedSizeInBytes; + private String iteratorTypeAndScanSize; + private Double samplingRate; + private boolean useRoundRobinIterator; + private String hexStringRVCOffset; + private Consistency consistency; + private HintNode.Hint hint; + private String serverSortedBy; + private String explainScanType; + private String tableName; + private String keyRanges; + private Long scanTimeRangeMin; + private Long scanTimeRangeMax; + private String serverWhereFilter; + private String serverDistinctFilter; + private Integer serverOffset; + private Long serverRowLimit; + private boolean serverArrayElementProjection; + private String serverAggregate; + private String clientFilterBy; + private String clientAggregate; + private String clientSortedBy; + private String clientAfterAggregate; + private String clientDistinctFilter; + private Integer clientOffset; + private Integer clientRowLimit; + private Integer clientSequenceCount; + private String clientCursorName; + private String clientSortAlgo; + private ExplainPlanAttributes rhsJoinQueryExplainPlan; + + public ExplainPlanAttributesBuilder() { + // default + } + + public ExplainPlanAttributesBuilder( + ExplainPlanAttributes explainPlanAttributes) { + this.abstractExplainPlan = + explainPlanAttributes.getAbstractExplainPlan(); + this.splitsChunk = explainPlanAttributes.getSplitsChunk(); + this.estimatedRows = explainPlanAttributes.getEstimatedRows(); + this.estimatedSizeInBytes = + explainPlanAttributes.getEstimatedSizeInBytes(); + this.iteratorTypeAndScanSize = explainPlanAttributes.getIteratorTypeAndScanSize(); + this.samplingRate = explainPlanAttributes.getSamplingRate(); + this.useRoundRobinIterator = + explainPlanAttributes.isUseRoundRobinIterator(); + this.hexStringRVCOffset = + explainPlanAttributes.getHexStringRVCOffset(); + this.consistency = explainPlanAttributes.getConsistency(); + this.hint = explainPlanAttributes.getHint(); + this.serverSortedBy = explainPlanAttributes.getServerSortedBy(); + this.explainScanType = explainPlanAttributes.getExplainScanType(); + this.tableName = explainPlanAttributes.getTableName(); + this.keyRanges = explainPlanAttributes.getKeyRanges(); + this.scanTimeRangeMin = explainPlanAttributes.getScanTimeRangeMin(); + this.scanTimeRangeMax = explainPlanAttributes.getScanTimeRangeMax(); + this.serverWhereFilter = + explainPlanAttributes.getServerWhereFilter(); + this.serverDistinctFilter = + explainPlanAttributes.getServerDistinctFilter(); + this.serverOffset = explainPlanAttributes.getServerOffset(); + this.serverRowLimit = explainPlanAttributes.getServerRowLimit(); + this.serverArrayElementProjection = + explainPlanAttributes.isServerArrayElementProjection(); + this.serverAggregate = explainPlanAttributes.getServerAggregate(); + this.clientFilterBy = explainPlanAttributes.getClientFilterBy(); + this.clientAggregate = explainPlanAttributes.getClientAggregate(); + this.clientSortedBy = explainPlanAttributes.getClientSortedBy(); + this.clientAfterAggregate = + explainPlanAttributes.getClientAfterAggregate(); + this.clientDistinctFilter = + explainPlanAttributes.getClientDistinctFilter(); + this.clientOffset = explainPlanAttributes.getClientOffset(); + this.clientRowLimit = explainPlanAttributes.getClientRowLimit(); + this.clientSequenceCount = + explainPlanAttributes.getClientSequenceCount(); + this.clientCursorName = explainPlanAttributes.getClientCursorName(); + this.clientSortAlgo = explainPlanAttributes.getClientSortAlgo(); + this.rhsJoinQueryExplainPlan = + explainPlanAttributes.getRhsJoinQueryExplainPlan(); + } + + public ExplainPlanAttributesBuilder setAbstractExplainPlan( + String abstractExplainPlan) { + this.abstractExplainPlan = abstractExplainPlan; + return this; + } + + public ExplainPlanAttributesBuilder setSplitsChunk( + Integer splitsChunk) { + this.splitsChunk = splitsChunk; + return this; + } + + public ExplainPlanAttributesBuilder setEstimatedRows( + Long estimatedRows) { + this.estimatedRows = estimatedRows; + return this; + } + + public ExplainPlanAttributesBuilder setEstimatedSizeInBytes( + Long estimatedSizeInBytes) { + this.estimatedSizeInBytes = estimatedSizeInBytes; + return this; + } + + public ExplainPlanAttributesBuilder setIteratorTypeAndScanSize( + String iteratorTypeAndScanSize) { + this.iteratorTypeAndScanSize = iteratorTypeAndScanSize; + return this; + } + + public ExplainPlanAttributesBuilder setSamplingRate( + Double samplingRate) { + this.samplingRate = samplingRate; + return this; + } + + public ExplainPlanAttributesBuilder setUseRoundRobinIterator( + boolean useRoundRobinIterator) { + this.useRoundRobinIterator = useRoundRobinIterator; + return this; + } + + public ExplainPlanAttributesBuilder setHexStringRVCOffset( + String hexStringRVCOffset) { + this.hexStringRVCOffset = hexStringRVCOffset; + return this; + } + + public ExplainPlanAttributesBuilder setConsistency( + Consistency consistency) { + this.consistency = consistency; + return this; + } + + public ExplainPlanAttributesBuilder setHint(HintNode.Hint hint) { + this.hint = hint; + return this; + } + + public ExplainPlanAttributesBuilder setServerSortedBy( + String serverSortedBy) { + this.serverSortedBy = serverSortedBy; + return this; + } + + public ExplainPlanAttributesBuilder setExplainScanType( + String explainScanType) { + this.explainScanType = explainScanType; + return this; + } + + public ExplainPlanAttributesBuilder setTableName(String tableName) { + this.tableName = tableName; + return this; + } + + public ExplainPlanAttributesBuilder setKeyRanges(String keyRanges) { + this.keyRanges = keyRanges; + return this; + } + + public ExplainPlanAttributesBuilder setScanTimeRangeMin( + Long scanTimeRangeMin) { + this.scanTimeRangeMin = scanTimeRangeMin; + return this; + } + + public ExplainPlanAttributesBuilder setScanTimeRangeMax( + Long scanTimeRangeMax) { + this.scanTimeRangeMax = scanTimeRangeMax; + return this; + } + + public ExplainPlanAttributesBuilder setServerWhereFilter( + String serverWhereFilter) { + this.serverWhereFilter = serverWhereFilter; + return this; + } + + public ExplainPlanAttributesBuilder setServerDistinctFilter( + String serverDistinctFilter) { + this.serverDistinctFilter = serverDistinctFilter; + return this; + } + + public ExplainPlanAttributesBuilder setServerOffset( + Integer serverOffset) { + this.serverOffset = serverOffset; + return this; + } + + public ExplainPlanAttributesBuilder setServerRowLimit( + Long serverRowLimit) { + this.serverRowLimit = serverRowLimit; + return this; + } + + public ExplainPlanAttributesBuilder setServerArrayElementProjection( + boolean serverArrayElementProjection) { + this.serverArrayElementProjection = serverArrayElementProjection; + return this; + } + + public ExplainPlanAttributesBuilder setServerAggregate( + String serverAggregate) { + this.serverAggregate = serverAggregate; + return this; + } + + public ExplainPlanAttributesBuilder setClientFilterBy( + String clientFilterBy) { + this.clientFilterBy = clientFilterBy; + return this; + } + + public ExplainPlanAttributesBuilder setClientAggregate( + String clientAggregate) { + this.clientAggregate = clientAggregate; + return this; + } + + public ExplainPlanAttributesBuilder setClientSortedBy( + String clientSortedBy) { + this.clientSortedBy = clientSortedBy; + return this; + } + + public ExplainPlanAttributesBuilder setClientAfterAggregate( + String clientAfterAggregate) { + this.clientAfterAggregate = clientAfterAggregate; + return this; + } + + public ExplainPlanAttributesBuilder setClientDistinctFilter( + String clientDistinctFilter) { + this.clientDistinctFilter = clientDistinctFilter; + return this; + } + + public ExplainPlanAttributesBuilder setClientOffset( + Integer clientOffset) { + this.clientOffset = clientOffset; + return this; + } + + public ExplainPlanAttributesBuilder setClientRowLimit( + Integer clientRowLimit) { + this.clientRowLimit = clientRowLimit; + return this; + } + + public ExplainPlanAttributesBuilder setClientSequenceCount( + Integer clientSequenceCount) { + this.clientSequenceCount = clientSequenceCount; + return this; + } + + public ExplainPlanAttributesBuilder setClientCursorName( + String clientCursorName) { + this.clientCursorName = clientCursorName; + return this; + } + + public ExplainPlanAttributesBuilder setClientSortAlgo( + String clientSortAlgo) { + this.clientSortAlgo = clientSortAlgo; + return this; + } + + public ExplainPlanAttributesBuilder setRhsJoinQueryExplainPlan( + ExplainPlanAttributes rhsJoinQueryExplainPlan) { + this.rhsJoinQueryExplainPlan = rhsJoinQueryExplainPlan; + return this; + } + + public ExplainPlanAttributes build() { + return new ExplainPlanAttributes(abstractExplainPlan, splitsChunk, + estimatedRows, estimatedSizeInBytes, iteratorTypeAndScanSize, + samplingRate, useRoundRobinIterator, hexStringRVCOffset, + consistency, hint, serverSortedBy, explainScanType, tableName, + keyRanges, scanTimeRangeMin, scanTimeRangeMax, + serverWhereFilter, serverDistinctFilter, + serverOffset, serverRowLimit, + serverArrayElementProjection, serverAggregate, + clientFilterBy, clientAggregate, clientSortedBy, + clientAfterAggregate, clientDistinctFilter, clientOffset, + clientRowLimit, clientSequenceCount, clientCursorName, + clientSortAlgo, rhsJoinQueryExplainPlan); + } + } +} diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/GroupByCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/GroupByCompiler.java index c47e9a0..12e1a46 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/GroupByCompiler.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/GroupByCompiler.java @@ -26,6 +26,8 @@ import java.util.List; import net.jcip.annotations.Immutable; import org.apache.hadoop.hbase.util.Pair; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.OrderPreservingTracker.Info; import org.apache.phoenix.compile.OrderPreservingTracker.Ordering; import org.apache.phoenix.coprocessor.BaseScannerRegionObserver; @@ -73,12 +75,18 @@ public class GroupByCompiler { @Override public void explain(List<String> planSteps, Integer limit) { } - + + @Override + public void explain(List<String> planSteps, Integer limit, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } + @Override public String getScanAttribName() { return null; } }; + public static final GroupByCompiler.GroupBy UNGROUPED_GROUP_BY = new GroupBy(new GroupByBuilder().setIsOrderPreserving(true).setIsUngroupedAggregate(true)) { @Override public GroupBy compile(StatementContext context, QueryPlan innerQueryPlan, Expression whereExpression) throws SQLException { @@ -89,7 +97,17 @@ public class GroupByCompiler { public void explain(List<String> planSteps, Integer limit) { planSteps.add(" SERVER AGGREGATE INTO SINGLE ROW"); } - + + @Override + public void explain(List<String> planSteps, Integer limit, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + planSteps.add(" SERVER AGGREGATE INTO SINGLE ROW"); + if (explainPlanAttributesBuilder != null) { + explainPlanAttributesBuilder.setServerAggregate( + "SERVER AGGREGATE INTO SINGLE ROW"); + } + } + @Override public String getScanAttribName() { return BaseScannerRegionObserver.UNGROUPED_AGG; @@ -335,14 +353,35 @@ public class GroupByCompiler { } public void explain(List<String> planSteps, Integer limit) { + explainUtil(planSteps, limit, null); + } + + private void explainUtil(List<String> planSteps, Integer limit, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + String serverAggregate; if (isUngroupedAggregate) { - planSteps.add(" SERVER AGGREGATE INTO SINGLE ROW"); - } else if (isOrderPreserving) { - planSteps.add(" SERVER AGGREGATE INTO ORDERED DISTINCT ROWS BY " + getExpressions() + (limit == null ? "" : " LIMIT " + limit + " GROUP" + (limit.intValue() == 1 ? "" : "S"))); + serverAggregate = "SERVER AGGREGATE INTO SINGLE ROW"; } else { - planSteps.add(" SERVER AGGREGATE INTO DISTINCT ROWS BY " + getExpressions() + (limit == null ? "" : " LIMIT " + limit + " GROUP" + (limit.intValue() == 1 ? "" : "S"))); + String groupLimit = limit == null ? "" : (" LIMIT " + limit + + " GROUP" + (limit == 1 ? "" : "S")); + if (isOrderPreserving) { + serverAggregate = "SERVER AGGREGATE INTO ORDERED DISTINCT ROWS BY " + + getExpressions() + groupLimit; + } else { + serverAggregate = "SERVER AGGREGATE INTO DISTINCT ROWS BY " + + getExpressions() + groupLimit; + } + } + planSteps.add(" " + serverAggregate); + if (explainPlanAttributesBuilder != null) { + explainPlanAttributesBuilder.setServerAggregate(serverAggregate); } } + + public void explain(List<String> planSteps, Integer limit, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + explainUtil(planSteps, limit, explainPlanAttributesBuilder); + } } /** diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/ListJarsQueryPlan.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/ListJarsQueryPlan.java index e7db5b1..ec77621 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/ListJarsQueryPlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/ListJarsQueryPlan.java @@ -37,6 +37,8 @@ import org.apache.hadoop.hbase.KeyValue.Type; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.GroupByCompiler.GroupBy; import org.apache.phoenix.compile.OrderByCompiler.OrderBy; import org.apache.phoenix.execute.visitor.QueryPlanVisitor; @@ -179,6 +181,11 @@ public class ListJarsQueryPlan implements QueryPlan { @Override public void explain(List<String> planSteps) { } + + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } }; } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/MutatingParallelIteratorFactory.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/MutatingParallelIteratorFactory.java index 213ff0a..37a87de 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/MutatingParallelIteratorFactory.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/MutatingParallelIteratorFactory.java @@ -27,6 +27,8 @@ import java.util.List; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.Scan; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.execute.MutationState; import org.apache.phoenix.iterate.ParallelIteratorFactory; import org.apache.phoenix.iterate.PeekingResultIterator; @@ -98,6 +100,11 @@ public abstract class MutatingParallelIteratorFactory implements ParallelIterato } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } + + @Override public void close() throws SQLException { try { /* diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/TraceQueryPlan.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/TraceQueryPlan.java index 7d36f0b..1558752 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/TraceQueryPlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/TraceQueryPlan.java @@ -33,6 +33,8 @@ import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.htrace.Sampler; import org.apache.htrace.TraceScope; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.GroupByCompiler.GroupBy; import org.apache.phoenix.compile.OrderByCompiler.OrderBy; import org.apache.phoenix.execute.visitor.QueryPlanVisitor; @@ -187,6 +189,11 @@ public class TraceQueryPlan implements QueryPlan { @Override public void explain(List<String> planSteps) { } + + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } }; } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java index 48a23eb..6724e6a 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java @@ -40,6 +40,8 @@ import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Pair; import org.apache.phoenix.cache.ServerCacheClient; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.GroupByCompiler.GroupBy; import org.apache.phoenix.compile.OrderByCompiler.OrderBy; import org.apache.phoenix.coprocessor.BaseScannerRegionObserver; @@ -1138,11 +1140,18 @@ public class UpsertCompiler { @Override public ExplainPlan getExplainPlan() throws SQLException { - List<String> queryPlanSteps = aggPlan.getExplainPlan().getPlanSteps(); - List<String> planSteps = Lists.newArrayListWithExpectedSize(queryPlanSteps.size()+1); + ExplainPlan explainPlan = aggPlan.getExplainPlan(); + List<String> queryPlanSteps = explainPlan.getPlanSteps(); + ExplainPlanAttributes explainPlanAttributes = + explainPlan.getPlanStepsAsAttributes(); + List<String> planSteps = + Lists.newArrayListWithExpectedSize(queryPlanSteps.size() + 1); + ExplainPlanAttributesBuilder newBuilder = + new ExplainPlanAttributesBuilder(explainPlanAttributes); + newBuilder.setAbstractExplainPlan("UPSERT ROWS"); planSteps.add("UPSERT ROWS"); planSteps.addAll(queryPlanSteps); - return new ExplainPlan(planSteps); + return new ExplainPlan(planSteps, newBuilder.build()); } @Override @@ -1418,11 +1427,18 @@ public class UpsertCompiler { @Override public ExplainPlan getExplainPlan() throws SQLException { - List<String> queryPlanSteps = queryPlan.getExplainPlan().getPlanSteps(); - List<String> planSteps = Lists.newArrayListWithExpectedSize(queryPlanSteps.size()+1); + ExplainPlan explainPlan = queryPlan.getExplainPlan(); + List<String> queryPlanSteps = explainPlan.getPlanSteps(); + ExplainPlanAttributes explainPlanAttributes = + explainPlan.getPlanStepsAsAttributes(); + List<String> planSteps = + Lists.newArrayListWithExpectedSize(queryPlanSteps.size() + 1); + ExplainPlanAttributesBuilder newBuilder = + new ExplainPlanAttributesBuilder(explainPlanAttributes); + newBuilder.setAbstractExplainPlan("UPSERT SELECT"); planSteps.add("UPSERT SELECT"); planSteps.addAll(queryPlanSteps); - return new ExplainPlan(planSteps); + return new ExplainPlan(planSteps, newBuilder.build()); } @Override diff --git a/phoenix-core/src/main/java/org/apache/phoenix/execute/BaseQueryPlan.java b/phoenix-core/src/main/java/org/apache/phoenix/execute/BaseQueryPlan.java index 2b10780..dace7c0 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/execute/BaseQueryPlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/execute/BaseQueryPlan.java @@ -28,6 +28,10 @@ import java.util.Map; import java.util.Set; import com.google.common.base.Optional; +import org.apache.commons.math3.util.Pair; +import org.apache.phoenix.compile.ExplainPlanAttributes; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; @@ -516,7 +520,10 @@ public abstract class BaseQueryPlan implements QueryPlan { } ResultIterator iterator = iterator(); - ExplainPlan explainPlan = new ExplainPlan(getPlanSteps(iterator)); + Pair<List<String>, ExplainPlanAttributes> planSteps = + getPlanStepsV2(iterator); + ExplainPlan explainPlan = new ExplainPlan(planSteps.getFirst(), + planSteps.getSecond()); iterator.close(); return explainPlan; } @@ -527,6 +534,15 @@ public abstract class BaseQueryPlan implements QueryPlan { return planSteps; } + private Pair<List<String>, ExplainPlanAttributes> getPlanStepsV2( + ResultIterator iterator) { + List<String> planSteps = Lists.newArrayListWithExpectedSize(5); + ExplainPlanAttributesBuilder builder = + new ExplainPlanAttributesBuilder(); + iterator.explain(planSteps, builder); + return new Pair<>(planSteps, builder.build()); + } + @Override public boolean isRowKeyOrdered() { return groupBy.isEmpty() ? orderBy.getOrderByExpressions().isEmpty() : groupBy.isOrderPreserving(); diff --git a/phoenix-core/src/main/java/org/apache/phoenix/execute/ClientAggregatePlan.java b/phoenix-core/src/main/java/org/apache/phoenix/execute/ClientAggregatePlan.java index aa99cab..f0199ac 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/execute/ClientAggregatePlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/execute/ClientAggregatePlan.java @@ -29,6 +29,9 @@ import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.phoenix.compile.ExplainPlan; +import org.apache.phoenix.compile.ExplainPlanAttributes; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.GroupByCompiler.GroupBy; import org.apache.phoenix.compile.OrderByCompiler.OrderBy; import org.apache.phoenix.compile.QueryPlan; @@ -220,45 +223,70 @@ public class ClientAggregatePlan extends ClientProcessingPlan { @Override public ExplainPlan getExplainPlan() throws SQLException { - List<String> planSteps = Lists.newArrayList(delegate.getExplainPlan().getPlanSteps()); + ExplainPlan explainPlan = delegate.getExplainPlan(); + List<String> planSteps = Lists.newArrayList(explainPlan.getPlanSteps()); + ExplainPlanAttributes explainPlanAttributes = + explainPlan.getPlanStepsAsAttributes(); + ExplainPlanAttributesBuilder newBuilder = + new ExplainPlanAttributesBuilder(explainPlanAttributes); if (where != null) { planSteps.add("CLIENT FILTER BY " + where.toString()); + newBuilder.setClientFilterBy(where.toString()); } if (groupBy.isEmpty()) { planSteps.add("CLIENT AGGREGATE INTO SINGLE ROW"); + newBuilder.setClientAggregate("CLIENT AGGREGATE INTO SINGLE ROW"); } else if (groupBy.isOrderPreserving()) { planSteps.add("CLIENT AGGREGATE INTO DISTINCT ROWS BY " + groupBy.getExpressions().toString()); + newBuilder.setClientAggregate("CLIENT AGGREGATE INTO DISTINCT ROWS BY " + + groupBy.getExpressions().toString()); } else if (useHashAgg) { planSteps.add("CLIENT HASH AGGREGATE INTO DISTINCT ROWS BY " + groupBy.getExpressions().toString()); + newBuilder.setClientAggregate("CLIENT HASH AGGREGATE INTO DISTINCT ROWS BY " + + groupBy.getExpressions().toString()); if (orderBy == OrderBy.FWD_ROW_KEY_ORDER_BY || orderBy == OrderBy.REV_ROW_KEY_ORDER_BY) { planSteps.add("CLIENT SORTED BY " + groupBy.getKeyExpressions().toString()); + newBuilder.setClientSortedBy( + groupBy.getKeyExpressions().toString()); } } else { planSteps.add("CLIENT SORTED BY " + groupBy.getKeyExpressions().toString()); planSteps.add("CLIENT AGGREGATE INTO DISTINCT ROWS BY " + groupBy.getExpressions().toString()); + newBuilder.setClientSortedBy(groupBy.getKeyExpressions().toString()); + newBuilder.setClientAggregate("CLIENT AGGREGATE INTO DISTINCT ROWS BY " + + groupBy.getExpressions().toString()); } if (having != null) { planSteps.add("CLIENT AFTER-AGGREGATION FILTER BY " + having.toString()); + newBuilder.setClientAfterAggregate("CLIENT AFTER-AGGREGATION FILTER BY " + + having.toString()); } if (statement.isDistinct() && statement.isAggregate()) { planSteps.add("CLIENT DISTINCT ON " + projector.toString()); + newBuilder.setClientDistinctFilter(projector.toString()); } if (offset != null) { planSteps.add("CLIENT OFFSET " + offset); + newBuilder.setClientOffset(offset); } if (orderBy.getOrderByExpressions().isEmpty()) { if (limit != null) { planSteps.add("CLIENT " + limit + " ROW LIMIT"); + newBuilder.setClientRowLimit(limit); } } else { planSteps.add("CLIENT" + (limit == null ? "" : " TOP " + limit + " ROW" + (limit == 1 ? "" : "S")) + " SORTED BY " + orderBy.getOrderByExpressions().toString()); + newBuilder.setClientRowLimit(limit); + newBuilder.setClientSortedBy( + orderBy.getOrderByExpressions().toString()); } if (context.getSequenceManager().getSequenceCount() > 0) { int nSequences = context.getSequenceManager().getSequenceCount(); planSteps.add("CLIENT RESERVE VALUES FROM " + nSequences + " SEQUENCE" + (nSequences == 1 ? "" : "S")); + newBuilder.setClientSequenceCount(nSequences); } - - return new ExplainPlan(planSteps); + + return new ExplainPlan(planSteps, newBuilder.build()); } @Override diff --git a/phoenix-core/src/main/java/org/apache/phoenix/execute/ClientScanPlan.java b/phoenix-core/src/main/java/org/apache/phoenix/execute/ClientScanPlan.java index f39e5bf..be4a65b 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/execute/ClientScanPlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/execute/ClientScanPlan.java @@ -23,6 +23,9 @@ import java.util.List; import org.apache.hadoop.hbase.client.Scan; import org.apache.phoenix.compile.ExplainPlan; +import org.apache.phoenix.compile.ExplainPlanAttributes; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.OrderByCompiler.OrderBy; import org.apache.phoenix.compile.QueryPlan; import org.apache.phoenix.compile.RowProjector; @@ -121,30 +124,44 @@ public class ClientScanPlan extends ClientProcessingPlan { @Override public ExplainPlan getExplainPlan() throws SQLException { - List<String> planSteps = Lists.newArrayList(delegate.getExplainPlan().getPlanSteps()); + ExplainPlan explainPlan = delegate.getExplainPlan(); + List<String> currentPlanSteps = explainPlan.getPlanSteps(); + ExplainPlanAttributes explainPlanAttributes = + explainPlan.getPlanStepsAsAttributes(); + List<String> planSteps = Lists.newArrayList(currentPlanSteps); + ExplainPlanAttributesBuilder newBuilder = + new ExplainPlanAttributesBuilder(explainPlanAttributes); if (where != null) { planSteps.add("CLIENT FILTER BY " + where.toString()); + newBuilder.setClientFilterBy(where.toString()); } if (!orderBy.getOrderByExpressions().isEmpty()) { if (offset != null) { planSteps.add("CLIENT OFFSET " + offset); + newBuilder.setClientOffset(offset); } planSteps.add("CLIENT" + (limit == null ? "" : " TOP " + limit + " ROW" + (limit == 1 ? "" : "S")) + " SORTED BY " + orderBy.getOrderByExpressions().toString()); + newBuilder.setClientRowLimit(limit); + newBuilder.setClientSortedBy( + orderBy.getOrderByExpressions().toString()); } else { if (offset != null) { planSteps.add("CLIENT OFFSET " + offset); + newBuilder.setClientOffset(offset); } if (limit != null) { planSteps.add("CLIENT " + limit + " ROW LIMIT"); + newBuilder.setClientRowLimit(limit); } } if (context.getSequenceManager().getSequenceCount() > 0) { int nSequences = context.getSequenceManager().getSequenceCount(); planSteps.add("CLIENT RESERVE VALUES FROM " + nSequences + " SEQUENCE" + (nSequences == 1 ? "" : "S")); + newBuilder.setClientSequenceCount(nSequences); } - - return new ExplainPlan(planSteps); + + return new ExplainPlan(planSteps, newBuilder.build()); } private static List<OrderBy> convertActualOutputOrderBy( diff --git a/phoenix-core/src/main/java/org/apache/phoenix/execute/CorrelatePlan.java b/phoenix-core/src/main/java/org/apache/phoenix/execute/CorrelatePlan.java index 68b1505..6d9afd6 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/execute/CorrelatePlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/execute/CorrelatePlan.java @@ -24,6 +24,9 @@ import java.util.List; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.phoenix.compile.ExplainPlan; +import org.apache.phoenix.compile.ExplainPlanAttributes; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.QueryPlan; import org.apache.phoenix.exception.SQLExceptionCode; import org.apache.phoenix.exception.SQLExceptionInfo; @@ -92,14 +95,33 @@ public class CorrelatePlan extends DelegateQueryPlan { public ExplainPlan getExplainPlan() throws SQLException { List<String> steps = Lists.newArrayList(); steps.add("NESTED-LOOP-JOIN (" + joinType.toString().toUpperCase() + ") TABLES"); - for (String step : delegate.getExplainPlan().getPlanSteps()) { - steps.add(" " + step); + ExplainPlan lhsExplainPlan = delegate.getExplainPlan(); + List<String> lhsPlanSteps = lhsExplainPlan.getPlanSteps(); + ExplainPlanAttributes lhsPlanAttributes = + lhsExplainPlan.getPlanStepsAsAttributes(); + ExplainPlanAttributesBuilder lhsPlanBuilder = + new ExplainPlanAttributesBuilder(lhsPlanAttributes); + lhsPlanBuilder.setAbstractExplainPlan("NESTED-LOOP-JOIN (" + + joinType.toString().toUpperCase() + ")"); + + for (String step : lhsPlanSteps) { + steps.add(" " + step); } steps.add("AND" + (rhsSchema.getFieldCount() == 0 ? " (SKIP MERGE)" : "")); - for (String step : rhs.getExplainPlan().getPlanSteps()) { - steps.add(" " + step); + + ExplainPlan rhsExplainPlan = rhs.getExplainPlan(); + List<String> rhsPlanSteps = rhsExplainPlan.getPlanSteps(); + ExplainPlanAttributes rhsPlanAttributes = + rhsExplainPlan.getPlanStepsAsAttributes(); + ExplainPlanAttributesBuilder rhsPlanBuilder = + new ExplainPlanAttributesBuilder(rhsPlanAttributes); + + lhsPlanBuilder.setRhsJoinQueryExplainPlan(rhsPlanBuilder.build()); + + for (String step : rhsPlanSteps) { + steps.add(" " + step); } - return new ExplainPlan(steps); + return new ExplainPlan(steps, lhsPlanBuilder.build()); } @Override @@ -217,6 +239,11 @@ public class CorrelatePlan extends DelegateQueryPlan { @Override public void explain(List<String> planSteps) { } + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } + private ProjectedValueTuple convertLhs(Tuple lhs) throws IOException { ProjectedValueTuple tuple; if (lhs instanceof ProjectedValueTuple) { diff --git a/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java b/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java index 71fb3fb..aa21ae2 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java @@ -295,6 +295,7 @@ public class HashJoinPlan extends DelegateQueryPlan { @Override public ExplainPlan getExplainPlan() throws SQLException { + // TODO : Support ExplainPlanAttributes for HashJoinPlan List<String> planSteps = Lists.newArrayList(delegate.getExplainPlan().getPlanSteps()); int count = subPlans.length; for (int i = 0; i < count; i++) { diff --git a/phoenix-core/src/main/java/org/apache/phoenix/execute/LiteralResultIterationPlan.java b/phoenix-core/src/main/java/org/apache/phoenix/execute/LiteralResultIterationPlan.java index a9f9d8e..10e9031 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/execute/LiteralResultIterationPlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/execute/LiteralResultIterationPlan.java @@ -26,6 +26,8 @@ import java.util.Map; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.Scan; import org.apache.phoenix.cache.ServerCacheClient.ServerCache; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.GroupByCompiler.GroupBy; import org.apache.phoenix.compile.OrderByCompiler.OrderBy; import org.apache.phoenix.compile.RowProjector; @@ -118,7 +120,12 @@ public class LiteralResultIterationPlan extends BaseQueryPlan { @Override public void explain(List<String> planSteps) { } - + + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } + }; if (context.getSequenceManager().getSequenceCount() > 0) { diff --git a/phoenix-core/src/main/java/org/apache/phoenix/execute/SortMergeJoinPlan.java b/phoenix-core/src/main/java/org/apache/phoenix/execute/SortMergeJoinPlan.java index 94f8452..51ff20f 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/execute/SortMergeJoinPlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/execute/SortMergeJoinPlan.java @@ -39,6 +39,9 @@ import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.util.Pair; import org.apache.phoenix.compile.ColumnResolver; import org.apache.phoenix.compile.ExplainPlan; +import org.apache.phoenix.compile.ExplainPlanAttributes; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.GroupByCompiler.GroupBy; import org.apache.phoenix.compile.OrderByCompiler.OrderBy; import org.apache.phoenix.compile.QueryCompiler; @@ -197,14 +200,33 @@ public class SortMergeJoinPlan implements QueryPlan { public ExplainPlan getExplainPlan() throws SQLException { List<String> steps = Lists.newArrayList(); steps.add("SORT-MERGE-JOIN (" + joinType.toString().toUpperCase() + ") TABLES"); - for (String step : lhsPlan.getExplainPlan().getPlanSteps()) { - steps.add(" " + step); + ExplainPlan lhsExplainPlan = lhsPlan.getExplainPlan(); + List<String> lhsPlanSteps = lhsExplainPlan.getPlanSteps(); + ExplainPlanAttributes lhsPlanAttributes = + lhsExplainPlan.getPlanStepsAsAttributes(); + ExplainPlanAttributesBuilder lhsPlanBuilder = + new ExplainPlanAttributesBuilder(lhsPlanAttributes); + lhsPlanBuilder.setAbstractExplainPlan("SORT-MERGE-JOIN (" + + joinType.toString().toUpperCase() + ")"); + + for (String step : lhsPlanSteps) { + steps.add(" " + step); } steps.add("AND" + (rhsSchema.getFieldCount() == 0 ? " (SKIP MERGE)" : "")); - for (String step : rhsPlan.getExplainPlan().getPlanSteps()) { - steps.add(" " + step); + + ExplainPlan rhsExplainPlan = rhsPlan.getExplainPlan(); + List<String> rhsPlanSteps = rhsExplainPlan.getPlanSteps(); + ExplainPlanAttributes rhsPlanAttributes = + rhsExplainPlan.getPlanStepsAsAttributes(); + ExplainPlanAttributesBuilder rhsPlanBuilder = + new ExplainPlanAttributesBuilder(rhsPlanAttributes); + + lhsPlanBuilder.setRhsJoinQueryExplainPlan(rhsPlanBuilder.build()); + + for (String step : rhsPlanSteps) { + steps.add(" " + step); } - return new ExplainPlan(steps); + return new ExplainPlan(steps, lhsPlanBuilder.build()); } @Override @@ -481,6 +503,11 @@ public class SortMergeJoinPlan implements QueryPlan { public void explain(List<String> planSteps) { } + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } + private void doInit(boolean lhs) throws SQLException { if(lhs) { nextLhsTuple = lhsIterator.next(); @@ -745,7 +772,12 @@ public class SortMergeJoinPlan implements QueryPlan { @Override public void explain(List<String> planSteps) { } - + + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } + private void advance(boolean lhs) throws SQLException { if (lhs) { lhsTuple = lhsIterator.next(); diff --git a/phoenix-core/src/main/java/org/apache/phoenix/execute/TupleProjectionPlan.java b/phoenix-core/src/main/java/org/apache/phoenix/execute/TupleProjectionPlan.java index 4b56c23..18b1aec 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/execute/TupleProjectionPlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/execute/TupleProjectionPlan.java @@ -27,6 +27,9 @@ import java.util.Map; import org.apache.hadoop.hbase.client.Scan; import org.apache.phoenix.compile.ColumnResolver; import org.apache.phoenix.compile.ExplainPlan; +import org.apache.phoenix.compile.ExplainPlanAttributes; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.OrderPreservingTracker; import org.apache.phoenix.compile.OrderPreservingTracker.Info; import org.apache.phoenix.compile.QueryPlan; @@ -151,12 +154,19 @@ public class TupleProjectionPlan extends DelegateQueryPlan { @Override public ExplainPlan getExplainPlan() throws SQLException { - List<String> planSteps = Lists.newArrayList(delegate.getExplainPlan().getPlanSteps()); + ExplainPlan explainPlan = delegate.getExplainPlan(); + List<String> planSteps = Lists.newArrayList(explainPlan.getPlanSteps()); + ExplainPlanAttributes explainPlanAttributes = + explainPlan.getPlanStepsAsAttributes(); if (postFilter != null) { planSteps.add("CLIENT FILTER BY " + postFilter.toString()); + ExplainPlanAttributesBuilder newBuilder = + new ExplainPlanAttributesBuilder(explainPlanAttributes); + newBuilder.setClientFilterBy(postFilter.toString()); + explainPlanAttributes = newBuilder.build(); } - return new ExplainPlan(planSteps); + return new ExplainPlan(planSteps, explainPlanAttributes); } @Override diff --git a/phoenix-core/src/main/java/org/apache/phoenix/execute/UnionPlan.java b/phoenix-core/src/main/java/org/apache/phoenix/execute/UnionPlan.java index cefd7b6..a6631d5 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/execute/UnionPlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/execute/UnionPlan.java @@ -29,6 +29,8 @@ import java.util.Set; import org.apache.hadoop.hbase.client.Scan; import org.apache.phoenix.compile.ExplainPlan; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.GroupByCompiler.GroupBy; import org.apache.phoenix.compile.OrderByCompiler.OrderBy; import org.apache.phoenix.compile.QueryPlan; @@ -182,15 +184,19 @@ public class UnionPlan implements QueryPlan { @Override public ExplainPlan getExplainPlan() throws SQLException { List<String> steps = new ArrayList<String>(); - steps.add("UNION ALL OVER " + this.plans.size() + " QUERIES"); + ExplainPlanAttributesBuilder builder = new ExplainPlanAttributesBuilder(); + String abstractExplainPlan = "UNION ALL OVER " + this.plans.size() + + " QUERIES"; + builder.setAbstractExplainPlan(abstractExplainPlan); + steps.add(abstractExplainPlan); ResultIterator iterator = iterator(); - iterator.explain(steps); + iterator.explain(steps, builder); // Indent plans steps nested under union, except last client-side merge/concat step (if there is one) int offset = !orderBy.getOrderByExpressions().isEmpty() && limit != null ? 2 : limit != null ? 1 : 0; for (int i = 1 ; i < steps.size()-offset; i++) { steps.set(i, " " + steps.get(i)); } - return new ExplainPlan(steps); + return new ExplainPlan(steps, builder.build()); } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/execute/UnnestArrayPlan.java b/phoenix-core/src/main/java/org/apache/phoenix/execute/UnnestArrayPlan.java index 896d1ed..19c9340 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/execute/UnnestArrayPlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/execute/UnnestArrayPlan.java @@ -24,6 +24,9 @@ import java.util.List; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.phoenix.compile.ExplainPlan; +import org.apache.phoenix.compile.ExplainPlanAttributes; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.QueryPlan; import org.apache.phoenix.compile.OrderByCompiler.OrderBy; import org.apache.phoenix.execute.visitor.QueryPlanVisitor; @@ -57,9 +60,15 @@ public class UnnestArrayPlan extends DelegateQueryPlan { @Override public ExplainPlan getExplainPlan() throws SQLException { - List<String> planSteps = delegate.getExplainPlan().getPlanSteps(); + ExplainPlan explainPlan = delegate.getExplainPlan(); + List<String> planSteps = explainPlan.getPlanSteps(); + ExplainPlanAttributes explainPlanAttributes = + explainPlan.getPlanStepsAsAttributes(); + ExplainPlanAttributesBuilder newBuilder = + new ExplainPlanAttributesBuilder(explainPlanAttributes); planSteps.add("UNNEST"); - return new ExplainPlan(planSteps); + newBuilder.setAbstractExplainPlan("UNNEST"); + return new ExplainPlan(planSteps, newBuilder.build()); } @Override diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseGroupedAggregatingResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseGroupedAggregatingResultIterator.java index 84d29ff..6b9f240 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseGroupedAggregatingResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseGroupedAggregatingResultIterator.java @@ -26,6 +26,8 @@ import java.util.List; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.expression.aggregator.Aggregator; import org.apache.phoenix.expression.aggregator.Aggregators; import org.apache.phoenix.schema.tuple.Tuple; @@ -103,4 +105,9 @@ public abstract class BaseGroupedAggregatingResultIterator implements resultIterator.explain(planSteps); } + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + resultIterator.explain(planSteps, explainPlanAttributesBuilder); + } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterator.java index 59ab5c9..17b6372 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterator.java @@ -17,6 +17,9 @@ */ package org.apache.phoenix.iterate; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; + import java.sql.SQLException; import java.util.List; @@ -38,4 +41,8 @@ public abstract class BaseResultIterator implements ResultIterator { public void explain(List<String> planSteps) { } + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java index c271487..151216c 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java @@ -72,6 +72,8 @@ import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Pair; import org.apache.phoenix.cache.ServerCacheClient.ServerCache; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.GroupByCompiler.GroupBy; import org.apache.phoenix.compile.QueryPlan; import org.apache.phoenix.compile.RowProjector; @@ -80,7 +82,6 @@ import org.apache.phoenix.compile.StatementContext; import org.apache.phoenix.coprocessor.BaseScannerRegionObserver; import org.apache.phoenix.coprocessor.HashJoinCacheNotFoundException; import org.apache.phoenix.coprocessor.UngroupedAggregateRegionObserver; -import org.apache.phoenix.exception.SQLExceptionCode; import org.apache.phoenix.exception.SQLExceptionInfo; import org.apache.phoenix.execute.MutationState; import org.apache.phoenix.execute.ScanPlan; @@ -1565,6 +1566,21 @@ public abstract class BaseResultIterators extends ExplainTable implements Result @Override public void explain(List<String> planSteps) { + explainUtil(planSteps, null); + } + + /** + * Utility to generate ExplainPlan steps. + * + * @param planSteps Add generated plan in list of planSteps. This argument + * is used to provide planSteps as whole statement consisting of + * list of Strings. + * @param explainPlanAttributesBuilder Add generated plan in attributes + * object. Having an API to provide planSteps as an object is easier + * while comparing individual attributes of ExplainPlan. + */ + private void explainUtil(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { boolean displayChunkCount = context.getConnection().getQueryServices().getProps().getBoolean( QueryServices.EXPLAIN_CHUNK_COUNT_ATTRIB, QueryServicesOptions.DEFAULT_EXPLAIN_CHUNK_COUNT); @@ -1575,32 +1591,65 @@ public abstract class BaseResultIterators extends ExplainTable implements Result QueryServices.EXPLAIN_ROW_COUNT_ATTRIB, QueryServicesOptions.DEFAULT_EXPLAIN_ROW_COUNT); buf.append(this.splits.size()).append("-CHUNK "); + if (explainPlanAttributesBuilder != null) { + explainPlanAttributesBuilder.setSplitsChunk(this.splits.size()); + } if (displayRowCount && estimatedRows != null) { buf.append(estimatedRows).append(" ROWS "); buf.append(estimatedSize).append(" BYTES "); + if (explainPlanAttributesBuilder != null) { + explainPlanAttributesBuilder.setEstimatedRows(estimatedRows); + explainPlanAttributesBuilder.setEstimatedSizeInBytes(estimatedSize); + } } } - buf.append(getName()).append(" ").append(size()).append("-WAY "); - - if(this.plan.getStatement().getTableSamplingRate()!=null){ - buf.append(plan.getStatement().getTableSamplingRate()/100D).append("-").append("SAMPLED "); + String iteratorTypeAndScanSize = getName() + " " + size() + "-WAY"; + buf.append(iteratorTypeAndScanSize).append(" "); + if (explainPlanAttributesBuilder != null) { + explainPlanAttributesBuilder.setIteratorTypeAndScanSize( + iteratorTypeAndScanSize); + } + + if (this.plan.getStatement().getTableSamplingRate() != null) { + Double samplingRate = plan.getStatement().getTableSamplingRate() / 100D; + buf.append(samplingRate).append("-").append("SAMPLED "); + if (explainPlanAttributesBuilder != null) { + explainPlanAttributesBuilder.setSamplingRate(samplingRate); + } } try { if (plan.useRoundRobinIterator()) { buf.append("ROUND ROBIN "); + if (explainPlanAttributesBuilder != null) { + explainPlanAttributesBuilder.setUseRoundRobinIterator(true); + } } } catch (SQLException e) { throw new RuntimeException(e); } - if(this.plan instanceof ScanPlan) { + if (this.plan instanceof ScanPlan) { ScanPlan scanPlan = (ScanPlan) this.plan; - if(scanPlan.getRowOffset().isPresent()) { - buf.append("With RVC Offset " + "0x" + Hex.encodeHexString(scanPlan.getRowOffset().get()) + " "); + if (scanPlan.getRowOffset().isPresent()) { + String rowOffset = + Hex.encodeHexString(scanPlan.getRowOffset().get()); + buf.append("With RVC Offset " + "0x") + .append(rowOffset) + .append(" "); + if (explainPlanAttributesBuilder != null) { + explainPlanAttributesBuilder.setHexStringRVCOffset( + "0x" + rowOffset); + } } } - explain(buf.toString(),planSteps); + explain(buf.toString(), planSteps, explainPlanAttributesBuilder); + } + + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + explainUtil(planSteps, explainPlanAttributesBuilder); } public Long getEstimatedRowCount() { diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ChunkedResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ChunkedResultIterator.java index 2fb7b72..8c8f810 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ChunkedResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ChunkedResultIterator.java @@ -26,6 +26,8 @@ import java.util.List; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.util.Bytes; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.QueryPlan; import org.apache.phoenix.compile.StatementContext; import org.apache.phoenix.execute.MutationState; @@ -132,6 +134,12 @@ public class ChunkedResultIterator implements PeekingResultIterator { } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + resultIterator.explain(planSteps, explainPlanAttributesBuilder); + } + + @Override public void close() throws SQLException { resultIterator.close(); } @@ -210,6 +218,12 @@ public class ChunkedResultIterator implements PeekingResultIterator { } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + delegate.explain(planSteps, explainPlanAttributesBuilder); + } + + @Override public void close() throws SQLException { delegate.close(); } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ClientHashAggregatingResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ClientHashAggregatingResultIterator.java index a07ea16..3a4a86c 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ClientHashAggregatingResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ClientHashAggregatingResultIterator.java @@ -35,6 +35,8 @@ import java.util.Objects; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.StatementContext; import org.apache.phoenix.compile.OrderByCompiler.OrderBy; import org.apache.phoenix.expression.Expression; @@ -144,6 +146,12 @@ public class ClientHashAggregatingResultIterator } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + resultIterator.explain(planSteps, explainPlanAttributesBuilder); + } + + @Override public String toString() { return "ClientHashAggregatingResultIterator [resultIterator=" + resultIterator + ", aggregators=" + aggregators + ", groupByExpressions=" diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ConcatResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ConcatResultIterator.java index fcc88aa..6a40177 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ConcatResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ConcatResultIterator.java @@ -20,6 +20,8 @@ package org.apache.phoenix.iterate; import java.sql.SQLException; import java.util.List; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.schema.tuple.Tuple; import org.apache.phoenix.util.ServerUtil; @@ -93,6 +95,14 @@ public class ConcatResultIterator implements PeekingResultIterator { } } + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + if (resultIterators != null) { + resultIterators.explain(planSteps, explainPlanAttributesBuilder); + } + } + private PeekingResultIterator currentIterator() throws SQLException { List<PeekingResultIterator> iterators = getIterators(); while (index < iterators.size()) { diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/CursorResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/CursorResultIterator.java index 7ff2785..c09f2e1 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/CursorResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/CursorResultIterator.java @@ -17,6 +17,8 @@ */ package org.apache.phoenix.iterate; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.schema.tuple.Tuple; import org.apache.phoenix.util.CursorUtil; @@ -55,6 +57,14 @@ public class CursorResultIterator implements ResultIterator { } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + delegate.explain(planSteps, explainPlanAttributesBuilder); + explainPlanAttributesBuilder.setClientCursorName(cursorName); + planSteps.add("CLIENT CURSOR " + cursorName); + } + + @Override public String toString() { return "CursorResultIterator [cursor=" + cursorName + "]"; } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/DelegateResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/DelegateResultIterator.java index 63b3142..375e0c3 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/DelegateResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/DelegateResultIterator.java @@ -20,6 +20,8 @@ package org.apache.phoenix.iterate; import java.sql.SQLException; import java.util.List; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.schema.tuple.Tuple; @@ -49,4 +51,10 @@ public class DelegateResultIterator implements ResultIterator { delegate.explain(planSteps); } + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + delegate.explain(planSteps, explainPlanAttributesBuilder); + } + } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/DistinctAggregatingResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/DistinctAggregatingResultIterator.java index 669b75a..106acea 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/DistinctAggregatingResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/DistinctAggregatingResultIterator.java @@ -25,6 +25,8 @@ import java.util.Set; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.phoenix.compile.ColumnProjector; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.RowProjector; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.aggregator.Aggregator; @@ -158,6 +160,15 @@ public class DistinctAggregatingResultIterator implements AggregatingResultItera } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + delegate.explain(planSteps, explainPlanAttributesBuilder); + explainPlanAttributesBuilder.setClientDistinctFilter( + rowProjector.toString()); + planSteps.add("CLIENT DISTINCT ON " + rowProjector.toString()); + } + + @Override public Aggregator[] aggregate(Tuple result) { return delegate.aggregate(result); } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java index 1aaa3f9..31713d9 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java @@ -31,6 +31,8 @@ import org.apache.hadoop.hbase.filter.PageFilter; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.io.TimeRange; import org.apache.hadoop.hbase.util.Bytes; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.GroupByCompiler.GroupBy; import org.apache.phoenix.compile.OrderByCompiler.OrderBy; import org.apache.phoenix.compile.ScanRanges; @@ -78,7 +80,8 @@ public abstract class ExplainTable { this.offset = offset; } - private boolean explainSkipScan(StringBuilder buf) { + private String explainSkipScan() { + StringBuilder buf = new StringBuilder(); ScanRanges scanRanges = context.getScanRanges(); if (scanRanges.isPointLookup()) { int keyCount = scanRanges.getPointLookupCount(); @@ -102,10 +105,11 @@ public abstract class ExplainTable { } else { buf.append("RANGE SCAN "); } - return scanRanges.useSkipScanFilter(); + return buf.toString(); } - - protected void explain(String prefix, List<String> planSteps) { + + protected void explain(String prefix, List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { StringBuilder buf = new StringBuilder(prefix); ScanRanges scanRanges = context.getScanRanges(); Scan scan = context.getScan(); @@ -119,19 +123,40 @@ public abstract class ExplainTable { if (OrderBy.REV_ROW_KEY_ORDER_BY.equals(orderBy)) { buf.append("REVERSE "); } + String scanTypeDetails; if (scanRanges.isEverything()) { - buf.append("FULL SCAN "); + scanTypeDetails = "FULL SCAN "; } else { - explainSkipScan(buf); + scanTypeDetails = explainSkipScan(); } + buf.append(scanTypeDetails); buf.append("OVER ").append(tableRef.getTable().getPhysicalName().getString()); if (!scanRanges.isPointLookup()) { - appendKeyRanges(buf); + buf.append(appendKeyRanges()); } planSteps.add(buf.toString()); + if (explainPlanAttributesBuilder != null) { + explainPlanAttributesBuilder.setConsistency(scan.getConsistency()); + if (hint.hasHint(Hint.SMALL)) { + explainPlanAttributesBuilder.setHint(Hint.SMALL); + } + if (OrderBy.REV_ROW_KEY_ORDER_BY.equals(orderBy)) { + explainPlanAttributesBuilder.setClientSortedBy("REVERSE"); + } + explainPlanAttributesBuilder.setExplainScanType(scanTypeDetails); + explainPlanAttributesBuilder.setTableName(tableRef.getTable() + .getPhysicalName().getString()); + if (!scanRanges.isPointLookup()) { + explainPlanAttributesBuilder.setKeyRanges(appendKeyRanges()); + } + } if (context.getScan() != null && tableRef.getTable().getRowTimestampColPos() != -1) { TimeRange range = context.getScan().getTimeRange(); planSteps.add(" ROW TIMESTAMP FILTER [" + range.getMin() + ", " + range.getMax() + ")"); + if (explainPlanAttributesBuilder != null) { + explainPlanAttributesBuilder.setScanTimeRangeMin(range.getMin()); + explainPlanAttributesBuilder.setScanTimeRangeMax(range.getMax()); + } } PageFilter pageFilter = null; @@ -154,16 +179,40 @@ public abstract class ExplainTable { } while (filterIterator.hasNext()); } if (whereFilter != null) { - planSteps.add(" SERVER FILTER BY " + (firstKeyOnlyFilter == null ? "" : "FIRST KEY ONLY AND ") + whereFilter.toString()); + String serverWhereFilter = "SERVER FILTER BY " + + (firstKeyOnlyFilter == null ? "" : "FIRST KEY ONLY AND ") + + whereFilter.toString(); + planSteps.add(" " + serverWhereFilter); + if (explainPlanAttributesBuilder != null) { + explainPlanAttributesBuilder.setServerWhereFilter(serverWhereFilter); + } } else if (firstKeyOnlyFilter != null) { planSteps.add(" SERVER FILTER BY FIRST KEY ONLY"); + if (explainPlanAttributesBuilder != null) { + explainPlanAttributesBuilder.setServerWhereFilter( + "SERVER FILTER BY FIRST KEY ONLY"); + } } if (distinctFilter != null) { - planSteps.add(" SERVER DISTINCT PREFIX FILTER OVER "+groupBy.getExpressions().toString()); + String serverDistinctFilter = "SERVER DISTINCT PREFIX FILTER OVER " + + groupBy.getExpressions().toString(); + planSteps.add(" " + serverDistinctFilter); + if (explainPlanAttributesBuilder != null) { + explainPlanAttributesBuilder.setServerDistinctFilter(serverDistinctFilter); + } } if (!orderBy.getOrderByExpressions().isEmpty() && groupBy.isEmpty()) { // with GROUP BY, sort happens client-side - planSteps.add(" SERVER" + (limit == null ? "" : " TOP " + limit + " ROW" + (limit == 1 ? "" : "S")) - + " SORTED BY " + orderBy.getOrderByExpressions().toString()); + String orderByExpressions = "SERVER" + + (limit == null ? "" : " TOP " + limit + " ROW" + (limit == 1 ? "" : "S")) + + " SORTED BY " + orderBy.getOrderByExpressions().toString(); + planSteps.add(" " + orderByExpressions); + if (explainPlanAttributesBuilder != null) { + if (limit != null) { + explainPlanAttributesBuilder.setServerRowLimit(limit.longValue()); + } + explainPlanAttributesBuilder.setServerSortedBy( + orderBy.getOrderByExpressions().toString()); + } } else { if (offset != null) { planSteps.add(" SERVER OFFSET " + offset); @@ -171,15 +220,25 @@ public abstract class ExplainTable { if (pageFilter != null) { planSteps.add(" SERVER " + pageFilter.getPageSize() + " ROW LIMIT"); } + if (explainPlanAttributesBuilder != null) { + explainPlanAttributesBuilder.setServerOffset(offset); + if (pageFilter != null) { + explainPlanAttributesBuilder.setServerRowLimit( + pageFilter.getPageSize()); + } + } } Integer groupByLimit = null; byte[] groupByLimitBytes = scan.getAttribute(BaseScannerRegionObserver.GROUP_BY_LIMIT); if (groupByLimitBytes != null) { groupByLimit = (Integer) PInteger.INSTANCE.toObject(groupByLimitBytes); } - groupBy.explain(planSteps, groupByLimit); + groupBy.explain(planSteps, groupByLimit, explainPlanAttributesBuilder); if (scan.getAttribute(BaseScannerRegionObserver.SPECIFIC_ARRAY_INDEX) != null) { planSteps.add(" SERVER ARRAY ELEMENT PROJECTION"); + if (explainPlanAttributesBuilder != null) { + explainPlanAttributesBuilder.setServerArrayElementProjection(true); + } } } @@ -292,11 +351,12 @@ public abstract class ExplainTable { buf.append(','); } } - - private void appendKeyRanges(StringBuilder buf) { + + private String appendKeyRanges() { + final StringBuilder buf = new StringBuilder(); ScanRanges scanRanges = context.getScanRanges(); if (scanRanges.isDegenerate() || scanRanges.isEverything()) { - return; + return ""; } buf.append(" ["); StringBuilder buf1 = new StringBuilder(); @@ -310,5 +370,6 @@ public abstract class ExplainTable { buf.append(buf2); } buf.setCharAt(buf.length()-1, ']'); + return buf.toString(); } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/FilterAggregatingResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/FilterAggregatingResultIterator.java index 5fd2028..bd47a78 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/FilterAggregatingResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/FilterAggregatingResultIterator.java @@ -21,6 +21,8 @@ import java.sql.SQLException; import java.util.List; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.aggregator.Aggregator; import org.apache.phoenix.schema.tuple.Tuple; @@ -76,9 +78,17 @@ public class FilterAggregatingResultIterator implements AggregatingResultIterat planSteps.add("CLIENT FILTER BY " + expression.toString()); } - @Override - public String toString() { - return "FilterAggregatingResultIterator [delegate=" + delegate - + ", expression=" + expression + ", ptr=" + ptr + "]"; - } + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + delegate.explain(planSteps, explainPlanAttributesBuilder); + explainPlanAttributesBuilder.setClientFilterBy(expression.toString()); + planSteps.add("CLIENT FILTER BY " + expression.toString()); + } + + @Override + public String toString() { + return "FilterAggregatingResultIterator [delegate=" + delegate + + ", expression=" + expression + ", ptr=" + ptr + "]"; + } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/FilterResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/FilterResultIterator.java index 65bcad2..bf97782 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/FilterResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/FilterResultIterator.java @@ -21,6 +21,8 @@ import java.sql.SQLException; import java.util.List; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.schema.tuple.Tuple; import org.apache.phoenix.schema.types.PBoolean; @@ -74,9 +76,17 @@ public class FilterResultIterator extends LookAheadResultIterator { planSteps.add("CLIENT FILTER BY " + expression.toString()); } - @Override - public String toString() { - return "FilterResultIterator [delegate=" + delegate + ", expression=" - + expression + ", ptr=" + ptr + "]"; - } + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + delegate.explain(planSteps, explainPlanAttributesBuilder); + explainPlanAttributesBuilder.setClientFilterBy(expression.toString()); + planSteps.add("CLIENT FILTER BY " + expression.toString()); + } + + @Override + public String toString() { + return "FilterResultIterator [delegate=" + delegate + ", expression=" + + expression + ", ptr=" + ptr + "]"; + } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/LimitingResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/LimitingResultIterator.java index 7cf8d3e..6e1c52d 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/LimitingResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/LimitingResultIterator.java @@ -20,6 +20,8 @@ package org.apache.phoenix.iterate; import java.sql.SQLException; import java.util.List; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.schema.tuple.Tuple; /** @@ -50,12 +52,20 @@ public class LimitingResultIterator extends DelegateResultIterator { @Override public void explain(List<String> planSteps) { super.explain(planSteps); - planSteps.add("CLIENT " + limit + " ROW LIMIT"); + planSteps.add("CLIENT " + limit + " ROW LIMIT"); } - @Override - public String toString() { - return "LimitingResultIterator [rowCount=" + rowCount + ", limit=" - + limit + "]"; - } + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + super.explain(planSteps, explainPlanAttributesBuilder); + explainPlanAttributesBuilder.setClientRowLimit(limit); + planSteps.add("CLIENT " + limit + " ROW LIMIT"); + } + + @Override + public String toString() { + return "LimitingResultIterator [rowCount=" + rowCount + ", limit=" + + limit + "]"; + } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/LookAheadResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/LookAheadResultIterator.java index 1e5f09e..f7c46d4 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/LookAheadResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/LookAheadResultIterator.java @@ -20,6 +20,8 @@ package org.apache.phoenix.iterate; import java.sql.SQLException; import java.util.List; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.schema.tuple.ResultTuple; import org.apache.phoenix.schema.tuple.Tuple; @@ -38,6 +40,12 @@ abstract public class LookAheadResultIterator implements PeekingResultIterator { } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + iterator.explain(planSteps, explainPlanAttributesBuilder); + } + + @Override public void close() throws SQLException { iterator.close(); } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/MaterializedComparableResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/MaterializedComparableResultIterator.java index a76f1e3..5808a0e 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/MaterializedComparableResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/MaterializedComparableResultIterator.java @@ -21,6 +21,8 @@ import java.sql.SQLException; import java.util.Comparator; import java.util.List; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.schema.tuple.Tuple; /** @@ -72,4 +74,10 @@ public class MaterializedComparableResultIterator public void explain(List<String> planSteps) { delegate.explain(planSteps); } + + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + delegate.explain(planSteps, explainPlanAttributesBuilder); + } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/MaterializedResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/MaterializedResultIterator.java index befaa2d..a8c75af 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/MaterializedResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/MaterializedResultIterator.java @@ -20,6 +20,8 @@ package org.apache.phoenix.iterate; import java.sql.SQLException; import java.util.*; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.schema.tuple.Tuple; @@ -107,4 +109,9 @@ public class MaterializedResultIterator implements PeekingResultIterator { @Override public void explain(List<String> planSteps) { } + + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/MergeSortRowKeyResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/MergeSortRowKeyResultIterator.java index 1da5142..16551b5 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/MergeSortRowKeyResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/MergeSortRowKeyResultIterator.java @@ -19,6 +19,8 @@ package org.apache.phoenix.iterate; import java.util.List; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.schema.tuple.Tuple; import org.apache.phoenix.util.TupleUtil; @@ -57,9 +59,17 @@ public class MergeSortRowKeyResultIterator extends MergeSortResultIterator { planSteps.add("CLIENT MERGE SORT"); } - @Override - public String toString() { - return "MergeSortRowKeyResultIterator [keyOffset=" + keyOffset - + ", factor=" + factor + "]"; - } + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + resultIterators.explain(planSteps, explainPlanAttributesBuilder); + explainPlanAttributesBuilder.setClientSortAlgo("CLIENT MERGE SORT"); + planSteps.add("CLIENT MERGE SORT"); + } + + @Override + public String toString() { + return "MergeSortRowKeyResultIterator [keyOffset=" + keyOffset + + ", factor=" + factor + "]"; + } } \ No newline at end of file diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/MergeSortTopNResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/MergeSortTopNResultIterator.java index 42429b1..eace244 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/MergeSortTopNResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/MergeSortTopNResultIterator.java @@ -21,6 +21,8 @@ import java.sql.SQLException; import java.util.List; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.OrderByExpression; import org.apache.phoenix.schema.tuple.Tuple; @@ -108,10 +110,26 @@ public class MergeSortTopNResultIterator extends MergeSortResultIterator { } } - @Override - public String toString() { - return "MergeSortTopNResultIterator [limit=" + limit + ", count=" - + count + ", orderByColumns=" + orderByColumns + ", ptr1=" - + ptr1 + ", ptr2=" + ptr2 + ",offset=" + offset + "]"; - } + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + resultIterators.explain(planSteps, explainPlanAttributesBuilder); + explainPlanAttributesBuilder.setClientSortAlgo("CLIENT MERGE SORT"); + planSteps.add("CLIENT MERGE SORT"); + if (offset > 0) { + explainPlanAttributesBuilder.setClientOffset(offset); + planSteps.add("CLIENT OFFSET " + offset); + } + if (limit > 0) { + explainPlanAttributesBuilder.setClientRowLimit(limit); + planSteps.add("CLIENT LIMIT " + limit); + } + } + + @Override + public String toString() { + return "MergeSortTopNResultIterator [limit=" + limit + ", count=" + + count + ", orderByColumns=" + orderByColumns + ", ptr1=" + + ptr1 + ", ptr2=" + ptr2 + ",offset=" + offset + "]"; + } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/OffsetResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/OffsetResultIterator.java index db53806..5c5a6d3 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/OffsetResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/OffsetResultIterator.java @@ -20,6 +20,8 @@ package org.apache.phoenix.iterate; import java.sql.SQLException; import java.util.List; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.schema.tuple.Tuple; /** @@ -52,6 +54,14 @@ public class OffsetResultIterator extends DelegateResultIterator { } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + super.explain(planSteps, explainPlanAttributesBuilder); + explainPlanAttributesBuilder.setClientOffset(offset); + planSteps.add("CLIENT OFFSET " + offset); + } + + @Override public String toString() { return "OffsetResultIterator [rowCount=" + rowCount + ", offset=" + offset + "]"; } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/OrderedResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/OrderedResultIterator.java index 5430226..a433759 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/OrderedResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/OrderedResultIterator.java @@ -31,6 +31,8 @@ import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.util.Bytes; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.execute.DescVarLengthFastByteComparisons; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.OrderByExpression; @@ -303,6 +305,19 @@ public class OrderedResultIterator implements PeekingResultIterator { } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + delegate.explain(planSteps, explainPlanAttributesBuilder); + explainPlanAttributesBuilder.setClientOffset(offset); + explainPlanAttributesBuilder.setClientRowLimit(limit); + explainPlanAttributesBuilder.setClientSortedBy( + orderByExpressions.toString()); + planSteps.add("CLIENT" + (offset == null || offset == 0 ? "" : " OFFSET " + offset) + + (limit == null ? "" : " TOP " + limit + " ROW" + (limit == 1 ? "" : "S")) + + " SORTED BY " + orderByExpressions.toString()); + } + + @Override public String toString() { return "OrderedResultIterator [thresholdBytes=" + thresholdBytes + ", limit=" + limit + ", offset=" + offset + ", delegate=" + delegate @@ -356,6 +371,11 @@ public class OrderedResultIterator implements PeekingResultIterator { } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } + + @Override public void close() throws SQLException { try { queueEntries.close(); diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/PeekingResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/PeekingResultIterator.java index 9470d56..f4a193e 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/PeekingResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/PeekingResultIterator.java @@ -20,6 +20,8 @@ package org.apache.phoenix.iterate; import java.sql.SQLException; import java.util.List; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.schema.tuple.Tuple; @@ -51,6 +53,11 @@ public interface PeekingResultIterator extends ResultIterator { @Override public void explain(List<String> planSteps) { } + + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } }; /** diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ResultIterator.java index e2127f8..f721456 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ResultIterator.java @@ -20,6 +20,8 @@ package org.apache.phoenix.iterate; import java.sql.SQLException; import java.util.List; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.schema.tuple.Tuple; import org.apache.phoenix.util.SQLCloseable; @@ -38,6 +40,11 @@ public interface ResultIterator extends SQLCloseable { @Override public void explain(List<String> planSteps) { } + + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } }; /** @@ -49,4 +56,21 @@ public interface ResultIterator extends SQLCloseable { public Tuple next() throws SQLException; public void explain(List<String> planSteps); + + /** + * Generate ExplainPlan steps and add steps as list of Strings in + * planSteps argument as readable statement as well as add same generated + * steps in explainPlanAttributesBuilder so that we prepare ExplainPlan + * result as an attribute object useful to retrieve individual plan step + * attributes. + * + * @param planSteps Add generated plan in list of planSteps. This argument + * is used to provide planSteps as whole statement consisting of + * list of Strings. + * @param explainPlanAttributesBuilder Add generated plan in attributes + * object. Having an API to provide planSteps as an object is easier + * while comparing individual attributes of ExplainPlan. + */ + void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder); } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ResultIterators.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ResultIterators.java index 16f8b41..8bc47cc 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ResultIterators.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ResultIterators.java @@ -21,6 +21,8 @@ import java.sql.SQLException; import java.util.List; import org.apache.hadoop.hbase.client.Scan; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.query.KeyRange; import org.apache.phoenix.util.SQLCloseable; @@ -30,4 +32,22 @@ public interface ResultIterators extends SQLCloseable { public List<List<Scan>> getScans(); public void explain(List<String> planSteps); public List<PeekingResultIterator> getIterators() throws SQLException; + + /** + * Generate ExplainPlan steps and add steps as list of Strings in + * planSteps argument as readable statement as well as add same generated + * steps in explainPlanAttributesBuilder so that we prepare ExplainPlan + * result as an attribute object useful to retrieve individual plan step + * attributes. + * + * @param planSteps Add generated plan in list of planSteps. This argument + * is used to provide planSteps as whole statement consisting of + * list of Strings. + * @param explainPlanAttributesBuilder Add generated plan in attributes + * object. Having an API to provide planSteps as an object is easier + * while comparing individual attributes of ExplainPlan. + */ + void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder); + } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/RoundRobinResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/RoundRobinResultIterator.java index bc77c98..232cdd6 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/RoundRobinResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/RoundRobinResultIterator.java @@ -28,6 +28,8 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.QueryPlan; import org.apache.phoenix.compile.StatementContext; import org.apache.phoenix.query.ConnectionQueryServices; @@ -154,6 +156,14 @@ public class RoundRobinResultIterator implements ResultIterator { } } + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + if (resultIterators != null) { + resultIterators.explain(planSteps, explainPlanAttributesBuilder); + } + } + @VisibleForTesting int getNumberOfParallelFetches() { return numParallelFetches; @@ -315,6 +325,12 @@ public class RoundRobinResultIterator implements ResultIterator { } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + delegate.explain(planSteps, explainPlanAttributesBuilder); + } + + @Override public Tuple peek() throws SQLException { if (tuple != null) { return tuple; } return delegate.peek(); diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/RowKeyOrderedAggregateResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/RowKeyOrderedAggregateResultIterator.java index 3c52e51..dc72d72 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/RowKeyOrderedAggregateResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/RowKeyOrderedAggregateResultIterator.java @@ -25,6 +25,8 @@ import java.sql.SQLException; import java.util.List; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.expression.aggregator.Aggregator; import org.apache.phoenix.expression.aggregator.Aggregators; import org.apache.phoenix.schema.tuple.SingleKeyValueTuple; @@ -104,6 +106,14 @@ public class RowKeyOrderedAggregateResultIterator extends LookAheadResultIterato } } + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + if (resultIterators != null) { + resultIterators.explain(planSteps, explainPlanAttributesBuilder); + } + } + private Tuple nextTuple() throws SQLException { List<PeekingResultIterator> iterators = getIterators(); while (index < iterators.size()) { diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ScanningResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ScanningResultIterator.java index 6c521c1..4cafb88 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ScanningResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ScanningResultIterator.java @@ -51,6 +51,8 @@ import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.client.metrics.ScanMetrics; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.monitoring.CombinableMetric; import org.apache.phoenix.monitoring.GlobalClientMetrics; import org.apache.phoenix.monitoring.ScanMetricsHolder; @@ -178,6 +180,11 @@ public class ScanningResultIterator implements ResultIterator { } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } + + @Override public String toString() { return "ScanningResultIterator [scanner=" + scanner + "]"; } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/SequenceResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/SequenceResultIterator.java index 80b5401..5674a6a 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/SequenceResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/SequenceResultIterator.java @@ -20,6 +20,8 @@ package org.apache.phoenix.iterate; import java.sql.SQLException; import java.util.List; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.SequenceManager; import org.apache.phoenix.schema.tuple.Tuple; @@ -55,9 +57,19 @@ public class SequenceResultIterator extends DelegateResultIterator { planSteps.add("CLIENT RESERVE VALUES FROM " + nSequences + " SEQUENCE" + (nSequences == 1 ? "" : "S")); } - @Override - public String toString() { - return "SequenceResultIterator [sequenceManager=" + sequenceManager - + "]"; - } + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + super.explain(planSteps, explainPlanAttributesBuilder); + int nSequences = sequenceManager.getSequenceCount(); + explainPlanAttributesBuilder.setClientSequenceCount(nSequences); + planSteps.add("CLIENT RESERVE VALUES FROM " + nSequences + + " SEQUENCE" + (nSequences == 1 ? "" : "S")); + } + + @Override + public String toString() { + return "SequenceResultIterator [sequenceManager=" + sequenceManager + + "]"; + } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/SerialIterators.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/SerialIterators.java index 1693421..4fd38c5 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/SerialIterators.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/SerialIterators.java @@ -29,6 +29,8 @@ import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Pair; import org.apache.phoenix.cache.ServerCacheClient.ServerCache; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.QueryPlan; import org.apache.phoenix.coprocessor.BaseScannerRegionObserver; import org.apache.phoenix.hbase.index.util.ImmutableBytesPtr; @@ -207,6 +209,11 @@ public class SerialIterators extends BaseResultIterators { public void explain(List<String> planSteps) {} @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } + + @Override public void close() throws SQLException { if (currentIterator != null) { currentIterator.close(); diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/SpoolingResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/SpoolingResultIterator.java index 6995e79..b2d3794 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/SpoolingResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/SpoolingResultIterator.java @@ -36,6 +36,8 @@ import org.apache.commons.io.output.DeferredFileOutputStream; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.io.WritableUtils; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.QueryPlan; import org.apache.phoenix.compile.StatementContext; import org.apache.phoenix.memory.MemoryManager; @@ -253,6 +255,11 @@ public class SpoolingResultIterator implements PeekingResultIterator { @Override public void explain(List<String> planSteps) { } + + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } } /** @@ -354,9 +361,19 @@ public class SpoolingResultIterator implements PeekingResultIterator { @Override public void explain(List<String> planSteps) { } + + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } } @Override public void explain(List<String> planSteps) { } + + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/TableResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/TableResultIterator.java index c576ad8..2ae9223 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/TableResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/TableResultIterator.java @@ -44,6 +44,8 @@ import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.util.Bytes; import org.apache.phoenix.cache.ServerCacheClient.ServerCache; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.QueryPlan; import org.apache.phoenix.coprocessor.BaseScannerRegionObserver; import org.apache.phoenix.coprocessor.HashJoinCacheNotFoundException; @@ -297,4 +299,10 @@ public class TableResultIterator implements ResultIterator { scanIterator.explain(planSteps); } + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + scanIterator.explain(planSteps, explainPlanAttributesBuilder); + } + } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/TableSnapshotResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/TableSnapshotResultIterator.java index 6f5e2ee..9cca642 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/TableSnapshotResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/TableSnapshotResultIterator.java @@ -28,6 +28,8 @@ import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.snapshot.RestoreSnapshotHelper; import org.apache.hadoop.hbase.util.FSUtils; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.mapreduce.util.PhoenixConfigurationUtil; import org.apache.phoenix.monitoring.ScanMetricsHolder; import org.apache.phoenix.schema.tuple.Tuple; @@ -171,9 +173,14 @@ public class TableSnapshotResultIterator implements ResultIterator { } } - @Override - public void explain(List<String> planSteps) { - // noop - } + @Override + public void explain(List<String> planSteps) { + // noop + } + + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/UnionResultIterators.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/UnionResultIterators.java index 910a514..a90e8a6 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/UnionResultIterators.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/UnionResultIterators.java @@ -22,6 +22,9 @@ import java.util.Collections; import java.util.List; import org.apache.hadoop.hbase.client.Scan; +import org.apache.phoenix.compile.ExplainPlanAttributes; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.compile.QueryPlan; import org.apache.phoenix.compile.StatementContext; import org.apache.phoenix.monitoring.OverAllQueryMetrics; @@ -128,8 +131,8 @@ public class UnionResultIterators implements ResultIterators { @Override public void explain(List<String> planSteps) { - for (int index=0; index < iterators.size(); index++) { - iterators.get(index).explain(planSteps); + for (PeekingResultIterator iterator : iterators) { + iterator.explain(planSteps); } } @@ -137,4 +140,27 @@ public class UnionResultIterators implements ResultIterators { public List<PeekingResultIterator> getIterators() throws SQLException { return iterators; } + + @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + boolean moreThanOneIters = false; + ExplainPlanAttributesBuilder lhsPointer = null; + // For more than one iterators, explainPlanAttributes will create + // chain of objects as lhs and rhs query plans. + for (PeekingResultIterator iterator : iterators) { + if (moreThanOneIters) { + ExplainPlanAttributesBuilder rhsBuilder = + new ExplainPlanAttributesBuilder(); + iterator.explain(planSteps, rhsBuilder); + ExplainPlanAttributes rhsPlans = rhsBuilder.build(); + lhsPointer.setRhsJoinQueryExplainPlan(rhsPlans); + lhsPointer = rhsBuilder; + } else { + iterator.explain(planSteps, explainPlanAttributesBuilder); + lhsPointer = explainPlanAttributesBuilder; + } + moreThanOneIters = true; + } + } } \ No newline at end of file diff --git a/phoenix-core/src/test/java/org/apache/phoenix/iterate/ConcatResultIteratorTest.java b/phoenix-core/src/test/java/org/apache/phoenix/iterate/ConcatResultIteratorTest.java index 67d5cd0..106aa9d 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/iterate/ConcatResultIteratorTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/iterate/ConcatResultIteratorTest.java @@ -29,6 +29,8 @@ import java.util.List; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.util.Bytes; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.query.KeyRange; import org.apache.phoenix.schema.tuple.SingleKeyValueTuple; import org.apache.phoenix.schema.tuple.Tuple; @@ -98,6 +100,12 @@ public class ConcatResultIteratorTest { } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + + } + + @Override public int size() { return results.size(); } diff --git a/phoenix-core/src/test/java/org/apache/phoenix/iterate/MaterializedResultIterators.java b/phoenix-core/src/test/java/org/apache/phoenix/iterate/MaterializedResultIterators.java index c4b0265..6efc211 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/iterate/MaterializedResultIterators.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/iterate/MaterializedResultIterators.java @@ -22,6 +22,8 @@ import java.util.Collections; import java.util.List; import org.apache.hadoop.hbase.client.Scan; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.query.KeyRange; /** @@ -42,6 +44,11 @@ public class MaterializedResultIterators implements ResultIterators { } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } + + @Override public int size() { return results.size(); } diff --git a/phoenix-core/src/test/java/org/apache/phoenix/iterate/MergeSortResultIteratorTest.java b/phoenix-core/src/test/java/org/apache/phoenix/iterate/MergeSortResultIteratorTest.java index 9b2e8de..3879405 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/iterate/MergeSortResultIteratorTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/iterate/MergeSortResultIteratorTest.java @@ -29,6 +29,8 @@ import java.util.List; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.util.Bytes; +import org.apache.phoenix.compile.ExplainPlanAttributes + .ExplainPlanAttributesBuilder; import org.apache.phoenix.query.KeyRange; import org.apache.phoenix.schema.tuple.SingleKeyValueTuple; import org.apache.phoenix.schema.tuple.Tuple; @@ -79,6 +81,11 @@ public class MergeSortResultIteratorTest { } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } + + @Override public int size() { return results.size(); } @@ -109,6 +116,11 @@ public class MergeSortResultIteratorTest { } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } + + @Override public int size() { return results.size(); } @@ -172,6 +184,11 @@ public class MergeSortResultIteratorTest { } @Override + public void explain(List<String> planSteps, + ExplainPlanAttributesBuilder explainPlanAttributesBuilder) { + } + + @Override public int size() { return results.size(); }