phoenix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamestay...@apache.org
Subject git commit: PHOENIX-994 Handle scans on local index table in case any best fit covering local index available (Rajeshbabu)
Date Fri, 23 May 2014 03:47:04 GMT
Repository: incubator-phoenix
Updated Branches:
  refs/heads/local-index 276de4a19 -> 16ad19025


PHOENIX-994 Handle scans on local index table in case any best fit covering local index available
(Rajeshbabu)


Project: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/commit/16ad1902
Tree: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/tree/16ad1902
Diff: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/diff/16ad1902

Branch: refs/heads/local-index
Commit: 16ad19025f0286434adc11de896694f3bd79420d
Parents: 276de4a
Author: James Taylor <jtaylor@salesforce.com>
Authored: Thu May 22 20:48:01 2014 -0700
Committer: James Taylor <jtaylor@salesforce.com>
Committed: Thu May 22 20:48:01 2014 -0700

----------------------------------------------------------------------
 .../phoenix/end2end/index/LocalIndexIT.java     |  90 +++++++++++
 .../TrackOrderPreservingExpressionCompiler.java |   2 +
 .../phoenix/coprocessor/ScanRegionObserver.java | 151 +++++++++++++++++--
 .../DefaultParallelIteratorRegionSplitter.java  |  15 +-
 .../phoenix/iterate/ParallelIterators.java      |   8 +-
 .../apache/phoenix/optimize/QueryOptimizer.java |  20 ++-
 .../org/apache/phoenix/schema/SaltingUtil.java  |  12 ++
 7 files changed, 280 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/16ad1902/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java
----------------------------------------------------------------------
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 6bc1b90..16743e4 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
@@ -46,6 +46,7 @@ import org.apache.phoenix.schema.PTable.IndexType;
 import org.apache.phoenix.schema.PTableKey;
 import org.apache.phoenix.schema.TableNotFoundException;
 import org.apache.phoenix.util.MetaDataUtil;
+import org.apache.phoenix.util.QueryUtil;
 import org.apache.phoenix.util.ReadOnlyProps;
 import org.apache.phoenix.util.TestUtil;
 import org.junit.BeforeClass;
@@ -220,4 +221,93 @@ public class LocalIndexIT extends BaseIndexIT {
         }
         indexTable.close();
     }
+
+    @Test
+    public void testLocalIndexScan() throws Exception {
+        createBaseTable(DATA_TABLE_NAME, null, "('e','i','o')");
+        Connection conn1 = DriverManager.getConnection(getUrl());
+        try{
+            conn1.createStatement().execute("UPSERT INTO " + DATA_TABLE_NAME + " values('b',1,2,'z')");
+            conn1.createStatement().execute("UPSERT INTO " + DATA_TABLE_NAME + " values('f',1,2,'a')");
+            conn1.createStatement().execute("UPSERT INTO " + DATA_TABLE_NAME + " values('j',2,4,'a')");
+            conn1.createStatement().execute("UPSERT INTO " + DATA_TABLE_NAME + " values('q',3,1,'c')");
+            conn1.commit();
+            conn1.createStatement().execute("CREATE LOCAL INDEX " + INDEX_TABLE_NAME + "
ON " + DATA_TABLE_NAME + "(v1)");
+            
+            ResultSet rs = conn1.createStatement().executeQuery("SELECT COUNT(*) FROM " +
INDEX_TABLE_NAME);
+            assertTrue(rs.next());
+            
+            HBaseAdmin admin = driver.getConnectionQueryServices(getUrl(), TestUtil.TEST_PROPERTIES).getAdmin();
+            int numRegions = admin.getTableRegions(TableName.valueOf(DATA_TABLE_NAME)).size();
+            
+            String query = "SELECT t_id, k1, k2,V1 FROM " + DATA_TABLE_NAME +" where v1='a'";
+            rs = conn1.createStatement().executeQuery("EXPLAIN "+ query);
+            
+            assertEquals(
+                "CLIENT PARALLEL " + numRegions + "-WAY RANGE SCAN OVER "
+                        + MetaDataUtil.getLocalIndexTableName(DATA_TABLE_NAME) + " [-32768,'a']",
+                        QueryUtil.getExplainPlan(rs));
+            
+            rs = conn1.createStatement().executeQuery(query);
+            assertTrue(rs.next());
+            assertEquals("f", rs.getString("t_id"));
+            assertEquals(1, rs.getInt("k1"));
+            assertEquals(2, rs.getInt("k2"));
+            assertTrue(rs.next());
+            assertEquals("j", rs.getString("t_id"));
+            assertEquals(2, rs.getInt("k1"));
+            assertEquals(4, rs.getInt("k2"));
+            
+            query = "SELECT t_id, k1, k2,V1 from " + DATA_TABLE_FULL_NAME + " order by V1,t_id";
+            rs = conn1.createStatement().executeQuery("EXPLAIN " + query);
+            
+            assertEquals(
+                "CLIENT PARALLEL " + numRegions + "-WAY FULL SCAN OVER "
+                        + MetaDataUtil.getLocalIndexTableName(DATA_TABLE_NAME)+"\n"
+                        + "    SERVER SORTED BY [V1, T_ID]\n" + "CLIENT MERGE SORT",
+                QueryUtil.getExplainPlan(rs));
+            
+            rs = conn1.createStatement().executeQuery(query);
+            assertTrue(rs.next());
+            assertEquals("f", rs.getString("t_id"));
+            assertEquals(1, rs.getInt("k1"));
+            assertEquals(2, rs.getInt("k2"));
+            assertEquals("a", rs.getString("V1"));
+            assertTrue(rs.next());
+            assertEquals("j", rs.getString("t_id"));
+            assertEquals(2, rs.getInt("k1"));
+            assertEquals(4, rs.getInt("k2"));
+            assertEquals("a", rs.getString("V1"));
+            assertTrue(rs.next());
+            assertEquals("q", rs.getString("t_id"));
+            assertEquals(3, rs.getInt("k1"));
+            assertEquals(1, rs.getInt("k2"));
+            assertEquals("c", rs.getString("V1"));
+            assertTrue(rs.next());
+            assertEquals("b", rs.getString("t_id"));
+            assertEquals(1, rs.getInt("k1"));
+            assertEquals(2, rs.getInt("k2"));
+            assertEquals("z", rs.getString("V1"));
+        } finally {
+            conn1.close();
+        }
+        
+    }
+
+    @Test
+    public void testIndexPlanSelectionIfBothGlobalAndLocalIndexesHasSameColumnsAndOrder()
throws Exception {
+        createBaseTable(DATA_TABLE_NAME, null, "('e','i','o')");
+        Connection conn1 = DriverManager.getConnection(getUrl());
+        conn1.createStatement().execute("UPSERT INTO "+DATA_TABLE_NAME+" values('b',1,2,'z')");
+        conn1.createStatement().execute("UPSERT INTO "+DATA_TABLE_NAME+" values('f',1,2,'a')");
+        conn1.createStatement().execute("UPSERT INTO "+DATA_TABLE_NAME+" values('j',2,4,'a')");
+        conn1.createStatement().execute("UPSERT INTO "+DATA_TABLE_NAME+" values('q',3,1,'c')");
+        conn1.commit();
+        conn1.createStatement().execute("CREATE LOCAL INDEX " + INDEX_TABLE_NAME + " ON "
+ DATA_TABLE_NAME + "(v1)");
+        conn1.createStatement().execute("CREATE INDEX " + INDEX_TABLE_NAME + "2" + " ON "
+ DATA_TABLE_NAME + "(v1)");
+        String query = "SELECT t_id, k1, k2,V1 FROM " + DATA_TABLE_NAME +" where v1='a'";
+        ResultSet rs1 = conn1.createStatement().executeQuery("EXPLAIN "+ query);
+        assertEquals("CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + INDEX_TABLE_NAME + "2" +
" ['a']",QueryUtil.getExplainPlan(rs1));
+        conn1.close();
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/16ad1902/phoenix-core/src/main/java/org/apache/phoenix/compile/TrackOrderPreservingExpressionCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/TrackOrderPreservingExpressionCompiler.java
b/phoenix-core/src/main/java/org/apache/phoenix/compile/TrackOrderPreservingExpressionCompiler.java
index ebf117d..615ee6d 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/TrackOrderPreservingExpressionCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/TrackOrderPreservingExpressionCompiler.java
@@ -36,6 +36,7 @@ import org.apache.phoenix.parse.SubtractParseNode;
 import org.apache.phoenix.schema.ColumnRef;
 import org.apache.phoenix.schema.PTable;
 import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.PTable.IndexType;
 import org.apache.phoenix.util.SchemaUtil;
 
 import com.google.common.collect.Lists;
@@ -69,6 +70,7 @@ public class TrackOrderPreservingExpressionCompiler extends ExpressionCompiler
{
         boolean isSharedViewIndex = table.getViewIndexId() != null;
         // TODO: util for this offset, as it's computed in numerous places
         positionOffset = (isSalted ? 1 : 0) + (isMultiTenant ? 1 : 0) + (isSharedViewIndex
? 1 : 0);
+        this.isOrderPreserving &= table.getIndexType() != IndexType.LOCAL;
         entries = Lists.newArrayListWithExpectedSize(expectedEntrySize);
         this.ordering = ordering;
     }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/16ad1902/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/ScanRegionObserver.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/ScanRegionObserver.java
b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/ScanRegionObserver.java
index 8c3c470..9d05f96 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/ScanRegionObserver.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/ScanRegionObserver.java
@@ -199,11 +199,11 @@ public class ScanRegionObserver extends BaseScannerRegionObserver {
             innerScanner = new HashJoinRegionScanner(s, p, j, tenantId, c.getEnvironment());
         }
         
-        final OrderedResultIterator iterator = deserializeFromScan(scan,innerScanner, offset);
         List<KeyValueColumnExpression> arrayKVRefs = new ArrayList<KeyValueColumnExpression>();
         Expression[] arrayFuncRefs = deserializeArrayPostionalExpressionInfoFromScan(
                 scan, innerScanner, arrayKVRefs);
-        innerScanner = getWrappedScanner(c, innerScanner, arrayKVRefs, arrayFuncRefs);
+        innerScanner = getWrappedScanner(c, innerScanner, arrayKVRefs, arrayFuncRefs, offset);
+        final OrderedResultIterator iterator = deserializeFromScan(scan,innerScanner, offset);
         if (iterator == null) {
             return innerScanner;
         }
@@ -291,9 +291,10 @@ public class ScanRegionObserver extends BaseScannerRegionObserver {
      * the same from a custom filter.
      * @param arrayFuncRefs 
      * @param arrayKVRefs 
+     * @param offset starting position in the rowkey.
      */
     private RegionScanner getWrappedScanner(final ObserverContext<RegionCoprocessorEnvironment>
c, final RegionScanner s, 
-           final List<KeyValueColumnExpression> arrayKVRefs, final Expression[] arrayFuncRefs)
{
+           final List<KeyValueColumnExpression> arrayKVRefs, final Expression[] arrayFuncRefs,
final int offset) {
         return new RegionScanner() {
 
             @Override
@@ -345,12 +346,16 @@ public class ScanRegionObserver extends BaseScannerRegionObserver {
             public boolean nextRaw(List<Cell> result) throws IOException {
                 try {
                     boolean next = s.nextRaw(result);
-                    if(result.size() == 0) {
-                        return next;
-                    } else if((arrayFuncRefs != null && arrayFuncRefs.length == 0)
|| arrayKVRefs.size() == 0) {
+                    if (result.size() == 0) {
                         return next;
+                    } 
+                    if (arrayFuncRefs != null && arrayFuncRefs.length > 0 &&
arrayKVRefs.size() > 0) {
+                        replaceArrayIndexElement(arrayKVRefs, arrayFuncRefs, result);
                     }
-                    replaceArrayIndexElement(arrayKVRefs, arrayFuncRefs, result);
+                    if (offset > 0) {
+                        wrapResultUsingOffset(result,offset);
+                    }
+                    // There is a scanattribute set to retrieve the specific array element
                     return next;
                 } catch (Throwable t) {
                     ServerUtil.throwIOException(c.getEnvironment().getRegion().getRegionNameAsString(),
t);
@@ -364,11 +369,14 @@ public class ScanRegionObserver extends BaseScannerRegionObserver {
                     boolean next = s.nextRaw(result, limit);
                     if (result.size() == 0) {
                         return next;
-                    } else if ((arrayFuncRefs != null && arrayFuncRefs.length ==
0) || arrayKVRefs.size() == 0) { 
-                        return next; 
+                    } 
+                    if (arrayFuncRefs != null && arrayFuncRefs.length > 0 &&
arrayKVRefs.size() > 0) { 
+                        replaceArrayIndexElement(arrayKVRefs, arrayFuncRefs, result);
+                    }
+                    if (offset > 0) {
+                        wrapResultUsingOffset(result,offset);
                     }
                     // There is a scanattribute set to retrieve the specific array element
-                    replaceArrayIndexElement(arrayKVRefs, arrayFuncRefs, result);
                     return next;
                 } catch (Throwable t) {
                     ServerUtil.throwIOException(c.getEnvironment().getRegion().getRegionNameAsString(),
t);
@@ -408,7 +416,128 @@ public class ScanRegionObserver extends BaseScannerRegionObserver {
                         QueryConstants.ARRAY_VALUE_COLUMN_QUALIFIER.length, HConstants.LATEST_TIMESTAMP,
                         Type.codeToType(rowKv.getTypeByte()), value, 0, value.length));
             }
-            
+
+            private void wrapResultUsingOffset(List<Cell> result, final int offset)
{
+                for (int i = 0; i < result.size(); i++) {
+                    final Cell cell = result.get(i);
+                    // TODO: Create DelegateCell class instead
+                    Cell newCell = new Cell() {
+
+                        @Override
+                        public byte[] getRowArray() {
+                            return cell.getRowArray();
+                        }
+
+                        @Override
+                        public int getRowOffset() {
+                            return cell.getRowOffset() + offset;
+                        }
+
+                        @Override
+                        public short getRowLength() {
+                            return (short)(cell.getRowLength() - offset);
+                        }
+
+                        @Override
+                        public byte[] getFamilyArray() {
+                            return cell.getFamilyArray();
+                        }
+
+                        @Override
+                        public int getFamilyOffset() {
+                            return cell.getFamilyOffset();
+                        }
+
+                        @Override
+                        public byte getFamilyLength() {
+                            return cell.getFamilyLength();
+                        }
+
+                        @Override
+                        public byte[] getQualifierArray() {
+                            return cell.getQualifierArray();
+                        }
+
+                        @Override
+                        public int getQualifierOffset() {
+                            return cell.getQualifierOffset();
+                        }
+
+                        @Override
+                        public int getQualifierLength() {
+                            return cell.getQualifierLength();
+                        }
+
+                        @Override
+                        public long getTimestamp() {
+                            return cell.getTimestamp();
+                        }
+
+                        @Override
+                        public byte getTypeByte() {
+                            return cell.getTypeByte();
+                        }
+
+                        @Override
+                        public long getMvccVersion() {
+                            return cell.getMvccVersion();
+                        }
+
+                        @Override
+                        public byte[] getValueArray() {
+                            return cell.getValueArray();
+                        }
+
+                        @Override
+                        public int getValueOffset() {
+                            return cell.getValueOffset();
+                        }
+
+                        @Override
+                        public int getValueLength() {
+                            return cell.getValueLength();
+                        }
+
+                        @Override
+                        public byte[] getTagsArray() {
+                            return cell.getTagsArray();
+                        }
+
+                        @Override
+                        public int getTagsOffset() {
+                            return cell.getTagsOffset();
+                        }
+
+                        @Override
+                        public short getTagsLength() {
+                            return cell.getTagsLength();
+                        }
+
+                        @Override
+                        public byte[] getValue() {
+                            return cell.getValue();
+                        }
+
+                        @Override
+                        public byte[] getFamily() {
+                            return cell.getFamily();
+                        }
+
+                        @Override
+                        public byte[] getQualifier() {
+                            return cell.getQualifier();
+                        }
+
+                        @Override
+                        public byte[] getRow() {
+                            return cell.getRow();
+                        }
+                    };
+                    // Wrap cell in cell that offsets row key
+                    result.set(i, newCell);
+                }
+            }
+
             @Override
             public long getMaxResultSize() {
                 return s.getMaxResultSize();

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/16ad1902/phoenix-core/src/main/java/org/apache/phoenix/iterate/DefaultParallelIteratorRegionSplitter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/DefaultParallelIteratorRegionSplitter.java
b/phoenix-core/src/main/java/org/apache/phoenix/iterate/DefaultParallelIteratorRegionSplitter.java
index 7fb99ff..2a22107 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/DefaultParallelIteratorRegionSplitter.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/DefaultParallelIteratorRegionSplitter.java
@@ -41,7 +41,9 @@ import org.apache.phoenix.query.QueryServices;
 import org.apache.phoenix.query.QueryServicesOptions;
 import org.apache.phoenix.query.StatsManager;
 import org.apache.phoenix.schema.PTable;
+import org.apache.phoenix.schema.PTableType;
 import org.apache.phoenix.schema.TableRef;
+import org.apache.phoenix.schema.PTable.IndexType;
 import org.apache.phoenix.util.ReadOnlyProps;
 
 
@@ -84,6 +86,10 @@ public class DefaultParallelIteratorRegionSplitter implements ParallelIteratorRe
         Scan scan = context.getScan();
         PTable table = tableRef.getTable();
         List<HRegionLocation> allTableRegions = context.getConnection().getQueryServices().getAllTableRegions(table.getPhysicalName().getBytes());
+
+        if (table.getType().equals(PTableType.INDEX) && table.getIndexType().equals(IndexType.LOCAL))
{
+            return filterRegions(allTableRegions, HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW);
+        }
         // If we're not salting, then we've already intersected the minMaxRange with the
scan range
         // so there's nothing to do here.
         return filterRegions(allTableRegions, scan.getStartRow(), scan.getStopRow());
@@ -140,7 +146,14 @@ public class DefaultParallelIteratorRegionSplitter implements ParallelIteratorRe
         // distributed across regions, using this scheme compensates for regions that
         // have more rows than others, by applying tighter splits and therefore spawning
         // off more scans over the overloaded regions.
-        int splitsPerRegion = regions.size() >= targetConcurrency ? 1 : (regions.size()
> targetConcurrency / 2 ? maxConcurrency : targetConcurrency) / regions.size();
+        PTable table = tableRef.getTable();
+        boolean localIndex = table.getType().equals(PTableType.INDEX) && table.getIndexType().equals(IndexType.LOCAL);
+        int splitsPerRegion;
+        if (localIndex) {
+            splitsPerRegion = 1;
+        } else {
+            splitsPerRegion = regions.size() >= targetConcurrency ? 1 : (regions.size()
> targetConcurrency / 2 ? maxConcurrency : targetConcurrency) / regions.size();
+        }
         splitsPerRegion = Math.min(splitsPerRegion, maxIntraRegionParallelization);
         // Create a multi-map of ServerName to List<KeyRange> which we'll use to round
robin from to ensure
         // that we keep each region server busy for each query.

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/16ad1902/phoenix-core/src/main/java/org/apache/phoenix/iterate/ParallelIterators.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ParallelIterators.java
b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ParallelIterators.java
index 804db96..3f72103 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ParallelIterators.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ParallelIterators.java
@@ -37,6 +37,7 @@ import org.apache.phoenix.parse.*;
 import org.apache.phoenix.parse.HintNode.Hint;
 import org.apache.phoenix.query.*;
 import org.apache.phoenix.schema.*;
+import org.apache.phoenix.schema.PTable.IndexType;
 import org.apache.phoenix.schema.PTable.ViewType;
 import org.apache.phoenix.util.*;
 import org.slf4j.Logger;
@@ -222,6 +223,7 @@ public class ParallelIterators extends ExplainTable implements ResultIterators
{
         List<PeekingResultIterator> iterators = new ArrayList<PeekingResultIterator>(numSplits);
         List<Pair<byte[],Future<PeekingResultIterator>>> futures = new
ArrayList<Pair<byte[],Future<PeekingResultIterator>>>(numSplits);
         final UUID scanId = UUID.randomUUID();
+        final boolean localIndex = this.tableRef.getTable().getType() == PTableType.INDEX
&& this.tableRef.getTable().getIndexType() == IndexType.LOCAL;
         try {
             ExecutorService executor = services.getExecutor();
             for (KeyRange split : splits) {
@@ -237,7 +239,11 @@ public class ParallelIterators extends ExplainTable implements ResultIterators
{
                         minMaxRange = SaltingUtil.addSaltByte(split.getLowerRange(), minMaxRange);
                         split = split.intersect(minMaxRange);
                     }
-                }
+                } else if (localIndex) {
+                    if (splitScan.getStartRow().length != 0 || splitScan.getStopRow().length
!= 0) {
+                        SaltingUtil.addRegionStartKeyToScanStartAndStopRows(split.getLowerRange(),
splitScan);
+                    }
+                } 
                 if (ScanUtil.intersectScanRange(splitScan, split.getLowerRange(), split.getUpperRange(),
this.context.getScanRanges().useSkipScanFilter())) {
                     // Delay the swapping of start/stop row until row so we don't muck with
the intersect logic
                     ScanUtil.swapStartStopRowIfReversed(splitScan);

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/16ad1902/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
----------------------------------------------------------------------
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 b275e3d..19133b9 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
@@ -43,6 +43,7 @@ import org.apache.phoenix.schema.PColumn;
 import org.apache.phoenix.schema.PDatum;
 import org.apache.phoenix.schema.PIndexState;
 import org.apache.phoenix.schema.PTable;
+import org.apache.phoenix.schema.PTable.IndexType;
 import org.apache.phoenix.schema.PTableType;
 
 import com.google.common.collect.Lists;
@@ -283,11 +284,11 @@ public class QueryOptimizer {
                 int c = plan2.getContext().getScanRanges().getRanges().size() - plan1.getContext().getScanRanges().getRanges().size();
                 // Account for potential view constants which are always bound
                 if (plan1 == dataPlan) { // plan2 is index plan. Ignore the viewIndexId if
present
-                    c += boundRanges - (table2.getViewIndexId() == null ? 0 : 1);
+                    c += boundRanges - (table2.getViewIndexId() == null || table2.getIndexType()
== IndexType.LOCAL ? 0 : 1);
                 } else { // plan1 is index plan. Ignore the viewIndexId if present
-                    c -= boundRanges - (table1.getViewIndexId() == null ? 0 : 1);
+                    c -= boundRanges - (table1.getViewIndexId() == null || table1.getIndexType()
== IndexType.LOCAL ? 0 : 1);
                 }
-                if (c != 0) return c;
+                if (c != 0 && table1.getIndexType() != IndexType.LOCAL &&
table2.getIndexType() != IndexType.LOCAL) return c;
                 if (plan1.getGroupBy()!=null && plan2.getGroupBy()!=null) {
                     if (plan1.getGroupBy().isOrderPreserving() != plan2.getGroupBy().isOrderPreserving())
{
                         return plan1.getGroupBy().isOrderPreserving() ? -1 : 1;
@@ -297,11 +298,20 @@ public class QueryOptimizer {
                 c = (table1.getColumns().size() - table1.getPKColumns().size()) - (table2.getColumns().size()
- table2.getPKColumns().size());
                 if (c != 0) return c;
                 
+                // If all things are equal, don't choose local index as it forces scan
+                // on every region.
+                if (table1.getIndexType() == IndexType.LOCAL) {
+                    return 1;
+                }
+                if (table2.getIndexType() == IndexType.LOCAL) {
+                    return -1;
+                }
+
                 // All things being equal, just use the table based on the Hint.USE_DATA_OVER_INDEX_TABLE
-                if (plan1.getTableRef().getTable().getType() == PTableType.INDEX) {
+                if (table1.getType() == PTableType.INDEX) {
                     return comparisonOfDataVersusIndexTable;
                 }
-                if (plan2.getTableRef().getTable().getType() == PTableType.INDEX) {
+                if (table2.getType() == PTableType.INDEX) {
                     return -comparisonOfDataVersusIndexTable;
                 }
                 

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/16ad1902/phoenix-core/src/main/java/org/apache/phoenix/schema/SaltingUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/SaltingUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/SaltingUtil.java
index 8ae43e3..c6a2b80 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/SaltingUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/SaltingUtil.java
@@ -19,6 +19,7 @@ package org.apache.phoenix.schema;
 
 import java.util.List;
 
+import org.apache.hadoop.hbase.client.Scan;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.phoenix.query.KeyRange;
 import org.apache.phoenix.schema.RowKeySchema.RowKeySchemaBuilder;
@@ -105,4 +106,15 @@ public class SaltingUtil {
         }
         return KeyRange.getKeyRange(lowerRange, upperRange);
     }
+
+    public static void addRegionStartKeyToScanStartAndStopRows(byte[] startKey, Scan scan)
{
+        byte[] newStartRow = new byte[scan.getStartRow().length + startKey.length];
+        System.arraycopy(startKey, 0, newStartRow, 0, startKey.length);
+        System.arraycopy(scan.getStartRow(), 0, newStartRow, startKey.length, scan.getStartRow().length);
+        scan.setStartRow(newStartRow);
+        byte[] newStopRow = new byte[scan.getStopRow().length + startKey.length];
+        System.arraycopy(startKey, 0, newStopRow, 0, startKey.length);
+        System.arraycopy(scan.getStopRow(), 0, newStopRow, startKey.length, scan.getStopRow().length);
+        scan.setStopRow(newStopRow);
+    }
 }


Mime
View raw message