Skip to content

Commit

Permalink
[#20635] YSQL: Model remote index filter in the base scans cost model
Browse files Browse the repository at this point in the history
Summary:
In case of an Index Scan, storage index filters are applied on secondary index
and reduce the number of base table lookups neded. Before this change, this was
not correctly modeled in the base scans cost model.

After this change, we identify filters that can apply to the secondary index.
These filters are applied on the rows that match the index conditions used for
LSM index lookup. We compute the selectivity of the index conditions and storage
index filters together to estimate the number of base table lookups.
Jira: DB-9633

Test Plan: ./yb_build.sh --java-test 'org.yb.pgsql.TestPgCostModelSeekNextEstimation'

Reviewers: tverona, tnayak

Reviewed By: tnayak

Subscribers: yql

Differential Revision: https://phorge.dev.yugabyte.com/D31751
  • Loading branch information
gauravk-in committed Mar 15, 2024
1 parent 53edd59 commit 8fe3336
Show file tree
Hide file tree
Showing 10 changed files with 983 additions and 348 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,42 @@ private void testSeekAndNextEstimationIndexScanHelper(
}
}

private void testSeekAndNextEstimationIndexScanHelper_IgnoreActualResults(
Statement stmt, String query,
String table_name, String index_name,
double expected_seeks,
double expected_nexts,
Integer expected_docdb_result_width) throws Exception {
double expected_seeks_lower_bound = expected_seeks * SEEK_LOWER_BOUND_FACTOR
- SEEK_FAULT_TOLERANCE_OFFSET;
double expected_seeks_upper_bound = expected_seeks * SEEK_UPPER_BOUND_FACTOR
+ SEEK_FAULT_TOLERANCE_OFFSET;
double expected_nexts_lower_bound = expected_nexts * NEXT_LOWER_BOUND_FACTOR
- NEXT_FAULT_TOLERANCE_OFFSET;
double expected_nexts_upper_bound = expected_nexts * NEXT_UPPER_BOUND_FACTOR
+ NEXT_FAULT_TOLERANCE_OFFSET;
try {
testExplainDebug(stmt, query,
makeTopLevelBuilder()
.plan(makePlanBuilder()
.nodeType(NODE_INDEX_SCAN)
.relationName(table_name)
.indexName(index_name)
.estimatedSeeks(Checkers.closed(expected_seeks_lower_bound,
expected_seeks_upper_bound))
.estimatedNexts(Checkers.closed(expected_nexts_lower_bound,
expected_nexts_upper_bound))
.estimatedDocdbResultWidth(Checkers.equal(expected_docdb_result_width))
.build())
.build());
}
catch (AssertionError e) {
LOG.info("Failed Query: " + query);
LOG.info(e.toString());
throw e;
}
}

private void testSeekAndNextEstimationSeqScanHelper(
Statement stmt, String query,
String table_name, double expected_seeks,
Expand Down Expand Up @@ -423,4 +459,29 @@ public void testSeekNextEstimationSeqScan() throws Exception {
T4_NAME, 67, 160065, 20);
}
}

@Test
public void testSeekNextEstimationStorageIndexFilters() throws Exception {
try (Statement stmt = this.connection2.createStatement()) {
stmt.execute("CREATE TABLE test (k1 INT, v1 INT)");
stmt.execute("CREATE INDEX test_index_k1 ON test (k1 ASC)");
stmt.execute("CREATE INDEX test_index_k1_v1 ON test (k1 ASC) INCLUDE (v1)");
stmt.execute("INSERT INTO test (SELECT s, s FROM generate_series(1, 100000) s)");
stmt.execute("ANALYZE test");

/* All rows matching the filter on k1 will be seeked in the base table, and the filter on v1
* will be applied on the base table.
*/
testSeekAndNextEstimationIndexScanHelper_IgnoreActualResults(stmt,
"/*+IndexScan(test test_index_k1) */ SELECT * FROM test WHERE k1 > 50000 and v1 > 80000",
"test", "test_index_k1", 50000, 50000, 10);

/* The filter on v1 will be executed on the included column in test_index_k1_v1. As a result,
* fewer seeks will be needed on the base table.
*/
testSeekAndNextEstimationIndexScanHelper_IgnoreActualResults(stmt,
"/*+IndexScan(test test_index_k1_v1) */ SELECT * FROM test WHERE k1 > 50000 and v1 > 80000",
"test", "test_index_k1_v1", 10000, 50000, 10);
}
}
}
Loading

0 comments on commit 8fe3336

Please sign in to comment.