Repository: phoenix Updated Branches: refs/heads/4.x-HBase-1.1 ee5683603 -> 4d344b347
PHOENIX-3005 Fixes for COUNT(DISTINCT...) with DistinctPrefixFilter and indexes. Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/4d344b34 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/4d344b34 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/4d344b34 Branch: refs/heads/4.x-HBase-1.1 Commit: 4d344b3475b4deb058406edd5a738d5e1e73cc37 Parents: ee56836 Author: Lars Hofhansl <la...@apache.org> Authored: Sun Jun 19 21:21:42 2016 -0700 Committer: Lars Hofhansl <la...@apache.org> Committed: Sun Jun 19 21:22:28 2016 -0700 ---------------------------------------------------------------------- .../phoenix/end2end/DistinctPrefixFilterIT.java | 27 ++++++++++++-------- .../apache/phoenix/compile/GroupByCompiler.java | 7 ++--- .../DistinctCountAggregateFunction.java | 6 ++--- .../phoenix/compile/QueryOptimizerTest.java | 24 +++++++++++++++++ 4 files changed, 46 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/4d344b34/phoenix-core/src/it/java/org/apache/phoenix/end2end/DistinctPrefixFilterIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/DistinctPrefixFilterIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DistinctPrefixFilterIT.java index 0310183..6ef8e73 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/DistinctPrefixFilterIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DistinctPrefixFilterIT.java @@ -34,14 +34,17 @@ public class DistinctPrefixFilterIT extends BaseHBaseManagedTimeTableReuseIT { conn.setAutoCommit(false); String ddl = "CREATE TABLE " + testTableF + " (prefix1 INTEGER NOT NULL, prefix2 INTEGER NOT NULL, prefix3 INTEGER NOT NULL, " + - "col1 FLOAT, CONSTRAINT pk PRIMARY KEY(prefix1, prefix2, prefix3))"; + "col1 FLOAT, col2 INTEGER, CONSTRAINT pk PRIMARY KEY(prefix1, prefix2, prefix3)) DISABLE_WAL=true, IMMUTABLE_ROWS=true"; createTestTable(getUrl(), ddl); ddl = "CREATE TABLE " + testTableV + " (prefix1 varchar NOT NULL, prefix2 varchar NOT NULL, prefix3 INTEGER NOT NULL, " + - "col1 FLOAT, CONSTRAINT pk PRIMARY KEY(prefix1, prefix2, prefix3))"; + "col1 FLOAT, col2 INTEGER, CONSTRAINT pk PRIMARY KEY(prefix1, prefix2, prefix3)) DISABLE_WAL=true, IMMUTABLE_ROWS=true"; createTestTable(getUrl(), ddl); + conn.prepareStatement("CREATE INDEX " + testTableF + "_idx ON "+testTableF+"(col2) DISABLE_WAL=true").execute(); + conn.prepareStatement("CREATE INDEX " + testTableV + "_idx ON "+testTableV+"(col2) DISABLE_WAL=true").execute(); + conn.prepareStatement("CREATE SEQUENCE " + testSeq + " CACHE 1000").execute(); insertPrefixF(1, 1); @@ -76,8 +79,7 @@ public class DistinctPrefixFilterIT extends BaseHBaseManagedTimeTableReuseIT { multiply(); multiply(); multiply(); - multiply(); - multiply(); // 512 per unique prefix + multiply(); // 256 per unique prefix } @Test @@ -150,7 +152,11 @@ public class DistinctPrefixFilterIT extends BaseHBaseManagedTimeTableReuseIT { testPlan("SELECT DISTINCT (prefix1, prefix2, prefix3) FROM "+testTable, false); testPlan("SELECT DISTINCT prefix1, prefix2, col1, prefix3 FROM "+testTable, false); testPlan("SELECT DISTINCT prefix1, prefix2, col1 FROM "+testTable, false); - testPlan("SELECT DISTINCT col1, prefix1, prefix2 FROM "+testTable, false);; + testPlan("SELECT DISTINCT col1, prefix1, prefix2 FROM "+testTable, false); + testPlan("SELECT DISTINCT col1 FROM "+testTable, false); + testPlan("SELECT COUNT(DISTINCT col1) FROM "+testTable, false); + testPlan("SELECT DISTINCT col2 FROM "+testTable, true); + testPlan("SELECT COUNT(DISTINCT col2) FROM "+testTable, true); testPlan("SELECT prefix1 FROM "+testTable+" GROUP BY prefix1", true); testPlan("SELECT COUNT(prefix1) FROM (SELECT prefix1 FROM "+testTable+" GROUP BY prefix1)", true); // aggregate over the group by, cannot optimize @@ -176,7 +182,7 @@ public class DistinctPrefixFilterIT extends BaseHBaseManagedTimeTableReuseIT { private void testPlan(String query, boolean optimizable) throws Exception { ResultSet rs = conn.createStatement().executeQuery("EXPLAIN "+query); - assertEquals(QueryUtil.getExplainPlan(rs).contains(PREFIX), optimizable); + assertEquals(optimizable, QueryUtil.getExplainPlan(rs).contains(PREFIX)); } @Test @@ -256,6 +262,7 @@ public class DistinctPrefixFilterIT extends BaseHBaseManagedTimeTableReuseIT { testCount("SELECT %s COUNT(DISTINCT prefix1), COUNT(DISTINCT (prefix1, prefix2)) FROM " + testTable + " WHERE col1 > 0.99", -1, -1); testCount("SELECT %s COUNT(DISTINCT col1) FROM " + testTable, -1); + testCount("SELECT %s COUNT(DISTINCT col2) FROM " + testTable, -1); } @Test @@ -333,7 +340,7 @@ public class DistinctPrefixFilterIT extends BaseHBaseManagedTimeTableReuseIT { private static void insertPrefixF(int prefix1, int prefix2) throws SQLException { String query = "UPSERT INTO " + testTableF - + "(prefix1, prefix2, prefix3, col1) VALUES(?,?,NEXT VALUE FOR "+testSeq+",rand())"; + + "(prefix1, prefix2, prefix3, col1, col2) VALUES(?,?,NEXT VALUE FOR "+testSeq+",rand(), trunc(rand()*1000))"; PreparedStatement stmt = conn.prepareStatement(query); stmt.setInt(1, prefix1); stmt.setInt(2, prefix2); @@ -342,7 +349,7 @@ public class DistinctPrefixFilterIT extends BaseHBaseManagedTimeTableReuseIT { private static void insertPrefixV(String prefix1, String prefix2) throws SQLException { String query = "UPSERT INTO " + testTableV - + "(prefix1, prefix2, prefix3, col1) VALUES(?,?,NEXT VALUE FOR "+testSeq+",rand())"; + + "(prefix1, prefix2, prefix3, col1, col2) VALUES(?,?,NEXT VALUE FOR "+testSeq+",rand(), trunc(rand()*1000))"; PreparedStatement stmt = conn.prepareStatement(query); stmt.setString(1, prefix1); stmt.setString(2, prefix2); @@ -351,9 +358,9 @@ public class DistinctPrefixFilterIT extends BaseHBaseManagedTimeTableReuseIT { private static void multiply() throws SQLException { conn.prepareStatement("UPSERT INTO " + testTableF - + " SELECT prefix1,prefix2,NEXT VALUE FOR "+testSeq+",rand() FROM "+testTableF).execute(); + + " SELECT prefix1,prefix2,NEXT VALUE FOR "+testSeq+",rand(), trunc(rand()*1000) FROM "+testTableF).execute(); conn.prepareStatement("UPSERT INTO " + testTableV - + " SELECT prefix1,prefix2,NEXT VALUE FOR "+testSeq+",rand() FROM "+testTableV).execute(); + + " SELECT prefix1,prefix2,NEXT VALUE FOR "+testSeq+",rand(), trunc(rand()*1000) FROM "+testTableV).execute(); conn.commit(); } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/4d344b34/phoenix-core/src/main/java/org/apache/phoenix/compile/GroupByCompiler.java ---------------------------------------------------------------------- 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 267d132..a405317 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 @@ -154,11 +154,8 @@ public class GroupByCompiler { isOrderPreserving = tracker.isOrderPreserving(); orderPreservingColumnCount = tracker.getOrderPreservingColumnCount(); } - if (isOrderPreserving) { - return new GroupBy.GroupByBuilder(this).setOrderPreservingColumnCount(orderPreservingColumnCount).build(); - } - if (isUngroupedAggregate) { - return UNGROUPED_GROUP_BY; + if (isOrderPreserving || isUngroupedAggregate) { + return new GroupBy.GroupByBuilder(this).setIsOrderPreserving(isOrderPreserving).setOrderPreservingColumnCount(orderPreservingColumnCount).build(); } List<Expression> expressions = Lists.newArrayListWithExpectedSize(this.expressions.size()); List<Expression> keyExpressions = expressions; http://git-wip-us.apache.org/repos/asf/phoenix/blob/4d344b34/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DistinctCountAggregateFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DistinctCountAggregateFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DistinctCountAggregateFunction.java index 6ce3c27..958f8fd 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DistinctCountAggregateFunction.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DistinctCountAggregateFunction.java @@ -21,16 +21,16 @@ import java.util.List; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; - import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.aggregator.Aggregator; import org.apache.phoenix.expression.aggregator.DistinctCountClientAggregator; import org.apache.phoenix.expression.aggregator.DistinctValueWithCountServerAggregator; +import org.apache.phoenix.parse.DistinctCountParseNode; import org.apache.phoenix.parse.FunctionParseNode.Argument; import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction; +import org.apache.phoenix.schema.tuple.Tuple; import org.apache.phoenix.schema.types.PDataType; import org.apache.phoenix.schema.types.PLong; -import org.apache.phoenix.schema.tuple.Tuple; import org.apache.phoenix.util.SchemaUtil; @@ -41,7 +41,7 @@ import org.apache.phoenix.util.SchemaUtil; * * @since 1.2.1 */ -@BuiltInFunction(name=DistinctCountAggregateFunction.NAME, args= {@Argument()} ) +@BuiltInFunction(name=DistinctCountAggregateFunction.NAME, nodeClass=DistinctCountParseNode.class, args= {@Argument()} ) public class DistinctCountAggregateFunction extends DelegateConstantToCountAggregateFunction { public static final String NAME = "DISTINCT_COUNT"; public static final String NORMALIZED_NAME = SchemaUtil.normalizeIdentifier(NAME); http://git-wip-us.apache.org/repos/asf/phoenix/blob/4d344b34/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java index c3345ba..5f452f1 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java @@ -613,6 +613,30 @@ public class QueryOptimizerTest extends BaseConnectionlessQueryTest { assertEquals("Query should not use index", PTableType.VIEW, plan.getTableRef().getTable().getType()); } + @Test + public void testDistinctPrefixOnVarcharIndex() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + conn.createStatement().execute("CREATE TABLE t (k INTEGER NOT NULL PRIMARY KEY, v1 VARCHAR, v2 VARCHAR)"); + conn.createStatement().execute("CREATE INDEX idx ON t(v1)"); + PhoenixStatement stmt = conn.createStatement().unwrap(PhoenixStatement.class); + QueryPlan plan = stmt.optimizeQuery("SELECT COUNT(DISTINCT v1) FROM t"); + assertTrue(plan.getGroupBy().isOrderPreserving()); + assertFalse(plan.getGroupBy().getKeyExpressions().isEmpty()); + assertEquals("IDX", plan.getTableRef().getTable().getTableName().getString()); + } + + @Test + public void testDistinctPrefixOnIntIndex() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + conn.createStatement().execute("CREATE TABLE t (k INTEGER NOT NULL PRIMARY KEY, v1 INTEGER, v2 VARCHAR)"); + conn.createStatement().execute("CREATE INDEX idx ON t(v1)"); + PhoenixStatement stmt = conn.createStatement().unwrap(PhoenixStatement.class); + QueryPlan plan = stmt.optimizeQuery("SELECT COUNT(DISTINCT v1) FROM t"); + assertTrue(plan.getGroupBy().isOrderPreserving()); + assertFalse(plan.getGroupBy().getKeyExpressions().isEmpty()); + assertEquals("IDX", plan.getTableRef().getTable().getTableName().getString()); + } + private void assertPlanDetails(PreparedStatement stmt, String expectedPkCols, String expectedPkColsDataTypes, boolean expectedHasOrderBy, int expectedLimit) throws SQLException { Connection conn = stmt.getConnection(); QueryPlan plan = PhoenixRuntime.getOptimizedQueryPlan(stmt);