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:
parent
24b5c3021d
commit
923094b4cd
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user