1
0
mirror of https://github.com/MariaDB/server.git synced 2025-04-18 21:44:20 +03:00

MDEV-36094 Row ID filtering for reverse-ordered scans

The fix for MDEV-34413 added support for Index Condition Pushdown with reverse
ordered scans.  This makes Rowid filtering work with reverse-ordered scans, too,
so enable it.  For example, InnoDB can now check the pushed index condition and
then check the rowid filter on success, in the ORDER BY ... DESC case.
This commit is contained in:
Dave Gosselin 2025-02-19 06:52:16 -05:00 committed by Dave Gosselin
parent 24b5c3021d
commit 923094b4cd
4 changed files with 51 additions and 56 deletions

View File

@ -29,6 +29,14 @@ EXPLAIN
"key": "t1_b",
"key_length": "5",
"used_key_parts": ["b"],
"rowid_filter": {
"range": {
"key": "t1_a",
"used_key_parts": ["a"]
},
"rows": 6,
"selectivity_pct": 60
},
"loops": 1,
"rows": 1,
"cost": "COST_REPLACED",
@ -66,6 +74,14 @@ EXPLAIN
"key": "t1_b",
"key_length": "5",
"used_key_parts": ["b"],
"rowid_filter": {
"range": {
"key": "t1_a",
"used_key_parts": ["a"]
},
"rows": 8,
"selectivity_pct": 80
},
"loops": 1,
"rows": 2,
"cost": "COST_REPLACED",
@ -107,6 +123,14 @@ EXPLAIN
"key": "t1_b",
"key_length": "5",
"used_key_parts": ["b"],
"rowid_filter": {
"range": {
"key": "t1_a",
"used_key_parts": ["a"]
},
"rows": 6,
"selectivity_pct": 60
},
"loops": 1,
"rows": 1,
"cost": "COST_REPLACED",

View File

@ -3752,7 +3752,6 @@ analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
# The following must NOT use Rowid Filter:
analyze format=json select * from t1
where
a =30100 and b in (30100,30101,30102)
@ -3778,9 +3777,23 @@ ANALYZE
"key_length": "5",
"used_key_parts": ["a"],
"ref": ["const"],
"rowid_filter": {
"range": {
"key": "b",
"used_key_parts": ["b"]
},
"rows": 252,
"selectivity_pct": 4.799085888,
"r_rows": 250,
"r_lookups": 250,
"r_selectivity_pct": 100,
"r_buffer_size": "REPLACED",
"r_filling_time_ms": "REPLACED"
},
"loops": 1,
"r_loops": 1,
"rows": 250,
"r_index_rows": 250,
"r_rows": 250,
"cost": "REPLACED",
"r_table_time_ms": "REPLACED",
@ -3870,6 +3883,19 @@ ANALYZE
"key_length": "5",
"used_key_parts": ["a"],
"ref": ["const"],
"rowid_filter": {
"range": {
"key": "b",
"used_key_parts": ["b"]
},
"rows": 252,
"selectivity_pct": 4.799085888,
"r_rows": 250,
"r_lookups": 2,
"r_selectivity_pct": 100,
"r_buffer_size": "REPLACED",
"r_filling_time_ms": "REPLACED"
},
"loops": 1,
"r_loops": 1,
"rows": 250,

View File

@ -810,7 +810,6 @@ from
insert into t1 (a,b,f1) values ( 110, 100, 12345);
analyze table t1;
--echo # The following must NOT use Rowid Filter:
--source include/analyze-format.inc
analyze format=json select * from t1
where

View File

@ -27056,47 +27056,6 @@ void compute_part_of_sort_key_for_equals(JOIN *join, TABLE *table,
@detail
- Disable "Range checked for each record" (Is this strictly necessary
here?)
- Disable Rowid Filtering.
RowidFilteringAndReverseScans:
Suppose we're computing
select * from t1
where
key1 between 10 and 20 and extra_condition
order by key1 desc
here the range access uses a reverse-ordered scan on (1 <= key1 <= 10) and
extra_condition is checked by either ICP or Rowid Filtering.
Also suppose that extra_condition happens to be false for rows of t1 that
do not satisfy the "10 <= key1 <= 20" condition.
For forward ordered range scan, the SQL layer will make these calls:
h->read_range_first(RANGE(10 <= key1 <= 20));
while (h->read_range_next()) { ... }
The storage engine sees the end endpoint of "key1<=20" and can stop scanning
as soon as it encounters a row with key1>20.
For backward-ordered range scan, the SQL layer will make these calls:
h->index_read_map(key1=20, HA_READ_PREFIX_LAST_OR_PREV);
while (h->index_prev()) {
if (cmp_key(h->record, "key1=10" )<0)
break; // end of range
...
}
Note that the check whether we've walked beyond the key=10 endpoint is
made at the SQL layer. The storage engine has no information about the left
endpoint of the interval we're scanning. If all rows before that endpoint
do not pass the Rowid Filter, the storage engine will enumerate the records
until the table start.
In MySQL, the API is extended with set_end_range() call so that the storage
engine "knows" when to stop scanning.
*/
static void prepare_for_reverse_ordered_access(JOIN_TAB *tab)
@ -27107,19 +27066,6 @@ static void prepare_for_reverse_ordered_access(JOIN_TAB *tab)
tab->use_quick= 1;
tab->read_first_record= join_init_read_record;
}
/*
Rowid filtering does not work with reverse scans so cancel it.
*/
{
/*
Rowid Filter is initialized at a later stage. It is not pushed to
the storage engine yet:
*/
DBUG_ASSERT(!tab->table->file->pushed_rowid_filter);
tab->range_rowid_filter_info= NULL;
delete tab->rowid_filter;
tab->rowid_filter= NULL;
}
}