This is an automated email from the ASF dual-hosted git repository. stoty pushed a commit to branch 5.1 in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/5.1 by this push: new de97d19052 PHOENIX-6983 Add hint to disable server merges for uncovered index queries de97d19052 is described below commit de97d19052a1ad6db2b4dce79bcff25332f4de03 Author: Istvan Toth <st...@apache.org> AuthorDate: Mon Jun 19 20:13:10 2023 +0200 PHOENIX-6983 Add hint to disable server merges for uncovered index queries --- .../end2end/index/GlobalIndexOptimizationIT.java | 39 +++++++++++++++++++++- .../apache/phoenix/optimize/QueryOptimizer.java | 23 ++++++++++--- .../java/org/apache/phoenix/parse/HintNode.java | 4 +++ .../apache/phoenix/compile/QueryCompilerTest.java | 20 +++++++---- 4 files changed, 74 insertions(+), 12 deletions(-) diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/GlobalIndexOptimizationIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/GlobalIndexOptimizationIT.java index 99f5997a6e..7df45185f0 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/GlobalIndexOptimizationIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/GlobalIndexOptimizationIT.java @@ -257,7 +257,44 @@ public class GlobalIndexOptimizationIT extends ParallelStatsDisabledIT { assertEquals(4, rs.getInt("k3")); assertEquals("z", rs.getString("V1")); assertFalse(rs.next()); - + + //Same as above, but with SKIP-SCAN-JOIN hint + query = "SELECT /*+ INDEX(" + dataTableName + " " + indexTableName + "), NO_INDEX_SERVER_MERGE */ t_id, k1, k2, k3, V1 from " + dataTableFullName + " where v1<='z' and k3 > 1 order by V1,t_id"; + rs = conn1.createStatement().executeQuery("EXPLAIN " + query); + + expected = + "CLIENT PARALLEL 1-WAY FULL SCAN OVER " + dataTableName + "\n" + + " SERVER FILTER BY K3 > 1\n" + + " SERVER SORTED BY \\[" + dataTableName + "\\.V1, " + dataTableName + "\\.T_ID\\]\n" + + "CLIENT MERGE SORT\n" + + " SKIP-SCAN-JOIN TABLE 0\n" + + " CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + indexTableName + " \\[\\*\\] - \\['z'\\]\n" + + " SERVER FILTER BY FIRST KEY ONLY\n" + + " DYNAMIC SERVER FILTER BY \\(\"" + dataTableName + "\\.T_ID\", \"" + dataTableName + "\\.K1\", \"" + dataTableName + "\\.K2\"\\) IN \\(\\(\\$\\d+\\.\\$\\d+, \\$\\d+\\.\\$\\d+, \\$\\d+\\.\\$\\d+\\)\\)"; + actual = QueryUtil.getExplainPlan(rs); + assertTrue("Expected:\n" + expected + "\nbut got\n" + actual, Pattern.matches(expected, actual)); + + 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(3, rs.getInt("k3")); + 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(2, rs.getInt("k3")); + assertEquals("a", rs.getString("V1")); + assertTrue(rs.next()); + assertEquals("b", rs.getString("t_id")); + assertEquals(1, rs.getInt("k1")); + assertEquals(2, rs.getInt("k2")); + assertEquals(4, rs.getInt("k3")); + assertEquals("z", rs.getString("V1")); + assertFalse(rs.next()); + query = "SELECT /*+ INDEX(" + dataTableName + " " + indexTableName + ")*/ t_id, V1, k3 from " + dataTableFullName + " where v1 <='z' group by v1,t_id, k3"; rs = conn1.createStatement().executeQuery("EXPLAIN " + query); expected = 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 d2eee0caaf..68d70e0cb3 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 @@ -341,9 +341,22 @@ public class QueryOptimizer { if (indexState == PIndexState.ACTIVE || indexState == PIndexState.PENDING_ACTIVE || (indexState == PIndexState.PENDING_DISABLE && isUnderPendingDisableThreshold(indexTableRef.getCurrentTime(), indexTable.getIndexDisableTimestamp()))) { try { + if (select.getHint().hasHint(HintNode.Hint.NO_INDEX_SERVER_MERGE)) { + String schemaNameStr = index.getSchemaName() == null ? null + : index.getSchemaName().getString(); + String tableNameStr = index.getTableName() == null ? null + : index.getTableName().getString(); + throw new ColumnNotFoundException(schemaNameStr, tableNameStr, null, "*"); + } // translate nodes that match expressions that are indexed to the associated column parse node - SelectStatement rewrittenIndexSelect = ParseNodeRewriter.rewrite(indexSelect, new IndexExpressionParseNodeRewriter(index, null, statement.getConnection(), indexSelect.getUdfParseNodes())); - QueryCompiler compiler = new QueryCompiler(statement, rewrittenIndexSelect, resolver, targetColumns, parallelIteratorFactory, dataPlan.getContext().getSequenceManager(), isProjected, true, dataPlans); + SelectStatement rewrittenIndexSelect = + ParseNodeRewriter.rewrite(indexSelect, + new IndexExpressionParseNodeRewriter(index, null, + statement.getConnection(), indexSelect.getUdfParseNodes())); + QueryCompiler compiler = + new QueryCompiler(statement, rewrittenIndexSelect, resolver, targetColumns, + parallelIteratorFactory, dataPlan.getContext().getSequenceManager(), + isProjected, true, dataPlans); QueryPlan plan = compiler.compile(); @@ -357,8 +370,10 @@ public class QueryOptimizer { if (plan.getProjector().getColumnCount() == nColumns) { return plan; } else if (index.getIndexType() == IndexType.GLOBAL) { - String schemaNameStr = index.getSchemaName()==null?null:index.getSchemaName().getString(); - String tableNameStr = index.getTableName()==null?null:index.getTableName().getString(); + String schemaNameStr = index.getSchemaName() == null ? null + : index.getSchemaName().getString(); + String tableNameStr = index.getTableName() == null ? null + : index.getTableName().getString(); throw new ColumnNotFoundException(schemaNameStr, tableNameStr, null, "*"); } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java index 60334ac3d3..baba60bc91 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java @@ -118,6 +118,10 @@ public class HintNode { * Issue https://issues.apache.org/jira/browse/PHOENIX-4751. */ HASH_AGGREGATE, + /** + * Do not use server merge for hinted uncovered indexes + */ + NO_INDEX_SERVER_MERGE }; private final Map<Hint,String> hints; diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java index 7d6a9ec3f4..29dc819270 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java @@ -7024,30 +7024,36 @@ public class QueryCompilerTest extends BaseConnectionlessQueryTest { @Test public void testUncoveredPhoenix6984() throws Exception { - // This only triggers with PHOENIX-6959 try (Connection conn = DriverManager.getConnection(getUrl()); Statement stmt = conn.createStatement()) { stmt.execute("CREATE TABLE D (\n" + "K1 CHAR(6) NOT NULL,\n" - + "K2 VARCHAR(22) NOT NULL,\n" + "K3 CHAR(2) NOT NULL,\n" - + "K4 VARCHAR(36) NOT NULL,\n" + "V1 TIMESTAMP,\n" + "V2 TIMESTAMP,\n" + + "K2 VARCHAR(22) NOT NULL,\n" + + "K3 CHAR(2) NOT NULL,\n" + + "K4 VARCHAR(36) NOT NULL,\n" + + "V1 TIMESTAMP,\n" + + "V2 TIMESTAMP,\n" + "CONSTRAINT PK_BILLING_ORDER PRIMARY KEY (K1,K2,K3,K4))"); stmt.execute("CREATE INDEX I ON D(K2, K1, K3, K4)"); String query = - "SELECT /*+ INDEX(D I) */ * " + "FROM D " + "WHERE " + "K2 = 'XXX' AND " + "SELECT /*+ INDEX(D I), NO_INDEX_SERVER_MERGE */ * " + + "FROM D " + + "WHERE K2 = 'XXX' AND " + "V2 >= TIMESTAMP '2023-05-31 23:59:59.000' AND " - + "V1 <= TIMESTAMP '2023-04-01 00:00:00.000' " + "ORDER BY V2 asc"; + + "V1 <= TIMESTAMP '2023-04-01 00:00:00.000' " + + "ORDER BY V2 asc"; ResultSet rs = stmt.executeQuery("EXPLAIN " + query); String explainPlan = QueryUtil.getExplainPlan(rs); assertEquals("CLIENT PARALLEL 1-WAY FULL SCAN OVER D\n" + " SERVER FILTER BY (V2 >= TIMESTAMP '2023-05-31 23:59:59.000'" + " AND V1 <= TIMESTAMP '2023-04-01 00:00:00.000')\n" - + " SERVER SORTED BY [D.V2]\n" + "CLIENT MERGE SORT\n" + + " SERVER SORTED BY [D.V2]\n" + + "CLIENT MERGE SORT\n" + " SKIP-SCAN-JOIN TABLE 0\n" + " CLIENT PARALLEL 1-WAY RANGE SCAN OVER I ['XXX']\n" + " SERVER FILTER BY FIRST KEY ONLY\n" + " DYNAMIC SERVER FILTER BY (\"D.K1\", \"D.K2\", \"D.K3\", \"D.K4\")" - + " IN (($3.$5, $3.$6, $3.$7, $3.$8))", + + " IN (($2.$4, $2.$5, $2.$6, $2.$7))", explainPlan); } }