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());

Reply via email to