This is an automated email from the ASF dual-hosted git repository.
larsh pushed a commit to branch 4.x-HBase-1.4
in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/4.x-HBase-1.4 by this push:
new c16b941 PHOENIX-5109; addendum, more tests, and test fixes.
c16b941 is described below
commit c16b9418b98d0dfe7612619b1e6e9367ca727b4c
Author: Lars Hofhansl <[email protected]>
AuthorDate: Fri Jan 25 19:20:42 2019 -0800
PHOENIX-5109; addendum, more tests, and test fixes.
---
.../apache/phoenix/end2end/index/LocalIndexIT.java | 57 +++++++++++++++++++++-
.../phoenix/end2end/index/MutableIndexIT.java | 5 +-
.../apache/phoenix/optimize/QueryOptimizer.java | 16 ++++--
3 files changed, 71 insertions(+), 7 deletions(-)
diff --git
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java
index 0c80db6..28e9c63 100644
---
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java
+++
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java
@@ -102,6 +102,61 @@ public class LocalIndexIT extends BaseLocalIndexIT {
}
@Test
+ public void testUseUncoveredLocalIndexWithPrefix() throws Exception {
+ String tableName = schemaName + "." + generateUniqueName();
+ String indexName = "IDX_" + generateUniqueName();
+ TableName physicalTableName =
SchemaUtil.getPhysicalTableName(tableName.getBytes(), isNamespaceMapped);
+ String indexPhysicalTableName = physicalTableName.getNameAsString();
+
+ Connection conn = getConnection();
+ conn.setAutoCommit(true);
+ if (isNamespaceMapped) {
+ conn.createStatement().execute("CREATE SCHEMA IF NOT EXISTS " +
schemaName);
+ }
+
+ conn.createStatement().execute("CREATE TABLE " + tableName
+ + " (pk1 INTEGER NOT NULL, pk2 INTEGER NOT NULL, pk3 INTEGER
NOT NULL, v1 FLOAT, v2 FLOAT, V3 INTEGER CONSTRAINT pk PRIMARY
KEY(pk1,pk2,pk3))");
+ conn.createStatement().execute("CREATE LOCAL INDEX " + indexName + "
ON " + tableName + "(pk1,pk2,v1,v2)");
+
+ // 1. same prefix length, no other restrictions, but v3 is in the
SELECT. Use the main table.
+ ResultSet rs = conn.createStatement().executeQuery("EXPLAIN SELECT *
FROM " + tableName + " WHERE pk1 = 3 AND pk2 = 4");
+ assertEquals(
+ "CLIENT PARALLEL 1-WAY RANGE SCAN OVER "
+ + physicalTableName + " [3,4]",
+ QueryUtil.getExplainPlan(rs));
+ rs.close();
+
+ // 2. same prefix length, no other restrictions. Only index columns
used. Use the index.
+ rs = conn.createStatement().executeQuery("EXPLAIN SELECT v2 FROM " +
tableName + " WHERE pk1 = 3 AND pk2 = 4");
+ assertEquals(
+ "CLIENT PARALLEL 1-WAY RANGE SCAN OVER "
+ + indexPhysicalTableName + " [1,3,4]\n"
+ + " SERVER FILTER BY FIRST KEY ONLY\n"
+ + "CLIENT MERGE SORT",
+ QueryUtil.getExplainPlan(rs));
+ rs.close();
+
+ // 3. same prefix length, but there's a column not on the index
+ rs = conn.createStatement().executeQuery("EXPLAIN SELECT v2 FROM " +
tableName + " WHERE pk1 = 3 AND pk2 = 4 AND v3 = 1");
+ assertEquals(
+ "CLIENT PARALLEL 1-WAY RANGE SCAN OVER "
+ + physicalTableName + " [3,4]\n"
+ + " SERVER FILTER BY V3 = 1",
+ QueryUtil.getExplainPlan(rs));
+ rs.close();
+
+ // 4. Longer prefix on the index, use it.
+ rs = conn.createStatement().executeQuery("EXPLAIN SELECT v2 FROM " +
tableName + " WHERE pk1 = 3 AND pk2 = 4 AND v1 = 3 AND v3 = 1");
+ assertEquals(
+ "CLIENT PARALLEL 1-WAY RANGE SCAN OVER "
+ + physicalTableName + " [1,3,4,3]\n"
+ + " SERVER FILTER BY FIRST KEY ONLY AND \"V3\" = 1\n"
+ + "CLIENT MERGE SORT",
+ QueryUtil.getExplainPlan(rs));
+ rs.close();
+ }
+
+ @Test
public void testUseUncoveredLocalIndex() throws Exception {
String tableName = schemaName + "." + generateUniqueName();
String indexName = "IDX_" + generateUniqueName();
@@ -198,7 +253,7 @@ public class LocalIndexIT extends BaseLocalIndexIT {
assertEquals(
"CLIENT PARALLEL 1-WAY RANGE SCAN OVER "
+ indexPhysicalTableName + " [1,2]\n"
- + " SERVER FILTER BY FIRST KEY ONLY AND \"V4\"
= 4\n"
+ + " SERVER FILTER BY FIRST KEY ONLY AND
TO_INTEGER(\"V4\") = 4\n"
+ "CLIENT MERGE SORT",
QueryUtil.getExplainPlan(rs));
rs.close();
diff --git
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexIT.java
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexIT.java
index 5415e87..adffd54 100644
---
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexIT.java
+++
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexIT.java
@@ -202,8 +202,9 @@ public class MutableIndexIT extends ParallelStatsDisabledIT
{
if(localIndex) {
query = "SELECT b.* from " + fullTableName + " where int_col1
= 4";
rs = conn.createStatement().executeQuery("EXPLAIN " + query);
- assertEquals("CLIENT PARALLEL 1-WAY RANGE SCAN OVER " +
fullTableName +" [1]\n" +
- " SERVER FILTER BY TO_INTEGER(\"INT_COL1\") =
4\nCLIENT MERGE SORT", QueryUtil.getExplainPlan(rs));
+ // this should *not* use an index, since neither int_col1, nor
all of the b.* columns are in the index
+ assertEquals("CLIENT PARALLEL 1-WAY FULL SCAN OVER " +
fullTableName +"\n" +
+ " SERVER FILTER BY A.INT_COL1 = 4",
QueryUtil.getExplainPlan(rs));
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals("varchar_b", rs.getString(1));
diff --git
a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
index 20c84cc..3223fbc 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
@@ -324,19 +324,22 @@ public class QueryOptimizer {
QueryPlan plan = compiler.compile();
- boolean optimizedOrderBy =
plan.getOrderBy().getOrderByExpressions().isEmpty() &&
-
!dataPlan.getOrderBy().getOrderByExpressions().isEmpty();
+ boolean optimizedSort =
+ plan.getOrderBy().getOrderByExpressions().isEmpty()
+ &&
!dataPlan.getOrderBy().getOrderByExpressions().isEmpty()
+ || plan.getGroupBy().isOrderPreserving()
+ &&
!dataPlan.getGroupBy().isOrderPreserving();
// If query doesn't have where clause, or the planner didn't
add any (bound) scan ranges, and some of
// columns to project/filter are missing in the index then we
need to get missing columns from main table
// for each row in local index. It's like full scan of both
local index and data table which is inefficient.
// Then we don't use the index. If all the columns to project
are present in the index
// then we can use the index even the query doesn't have where
clause.
- // We'll use the index anyway if it allowed us to optimize an
ORDER BY clause away.
+ // We'll use the index anyway if it allowed us to avoid a sort
operation.
if (index.getIndexType() == IndexType.LOCAL
&& (indexSelect.getWhere() == null
||
plan.getContext().getScanRanges().getBoundRanges().size() == 1)
- && !plan.getContext().getDataColumns().isEmpty() &&
!optimizedOrderBy) {
+ && !plan.getContext().getDataColumns().isEmpty() &&
!optimizedSort) {
return null;
}
indexTableRef = plan.getTableRef();
@@ -517,6 +520,11 @@ public class QueryOptimizer {
return plan1.getGroupBy().isOrderPreserving() ? -1 : 1;
}
}
+
+ // Use the plan that has fewer "dataColumns" (columns that
need to be merged in)
+ c = plan1.getContext().getDataColumns().size() -
plan2.getContext().getDataColumns().size();
+ if (c != 0) return c;
+
// Use smaller table (table with fewest kv columns)
if (!useDataOverIndexHint || (table1.getType() ==
PTableType.INDEX && table2.getType() == PTableType.INDEX)) {
c = (table1.getColumns().size() -
table1.getPKColumns().size()) - (table2.getColumns().size() -
table2.getPKColumns().size());