MDEV-38327 Do not use rowid filter in ref_to_range when the range method is index merge

Index merge and rowid filter should not be used together, however,
even if index merge is not chosen earlier in best_access_path, it may
be chosen again in make_join_select, inside ref_to_range. Therefore
this patch ensures that rowid filter is not used when index merge is
chosen there.
This commit is contained in:
Yuchen Pei 2026-01-21 11:47:43 +11:00 committed by Sergei Petrunia
commit 2c2a418591
4 changed files with 183 additions and 0 deletions

View file

@ -973,3 +973,69 @@ f1 f4 f5
DROP TABLE t1;
SET SESSION optimizer_switch='index_merge_sort_intersection=on';
SET SESSION optimizer_switch='rowid_filter=default';
#
# MDEV-38327 wrong result with index_merge_sort_intersection and rowid_filter=on
#
CREATE TABLE t1 (c int, b int, a int , d int, PRIMARY KEY (c), KEY ib (b), KEY iad (a,d));
INSERT INTO t1
SELECT seq + 1000000, FLOOR(seq / 5) % 1350 + 1000000, FLOOR(seq / 5) % 1350 , seq % 10 FROM seq_1_to_7000 ;
explain select a, b, c from t1 where a=1000 and b=1001000;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge ib,iad ib,iad 5,5 NULL 1 Using sort_intersect(ib,iad); Using where
select a, b, c from t1 where a=1000 and b=1001000;
a b c
1000 1001000 1005000
1000 1001000 1005001
1000 1001000 1005002
1000 1001000 1005003
1000 1001000 1005004
set optimizer_switch='index_merge_sort_intersection=on';
explain select a, b, c from t1 where a=1000 and b=1001000;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge ib,iad ib,iad 5,5 NULL 1 Using sort_intersect(ib,iad); Using where
select a, b, c from t1 where a=1000 and b=1001000;
a b c
1000 1001000 1005000
1000 1001000 1005001
1000 1001000 1005002
1000 1001000 1005003
1000 1001000 1005004
analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
explain select a, b, c from t1 where a=1000 and b=1001000;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge ib,iad ib,iad 5,5 NULL 1 Using sort_intersect(ib,iad); Using where
select a, b, c from t1 where a=1000 and b=1001000;
a b c
1000 1001000 1005000
1000 1001000 1005001
1000 1001000 1005002
1000 1001000 1005003
1000 1001000 1005004
drop table t1;
## MDEV-28878 case
CREATE TABLE t1 (f int);
INSERT INTO t1 VALUES (0),(4);
CREATE TABLE t2 (pk int, a int, b varchar(10), PRIMARY KEY (pk), KEY a (a), KEY b (b));
INSERT INTO t2 VALUES
(1,2,'v'),(2,3,'p'),(3,4,'p'),(4,2,'y'),(5,7,'q'),
(6,4,'a'),(7,1,'d'),(8,5,'a'),(9,5,'z'),(10,1,'t'),
(11,1,'y'),(12,5,'o'),(13,4,'a'),(14,5,'s'),(15,5,'m');
ANALYZE TABLE t1, t2 PERSISTENT FOR ALL;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
test.t2 analyze status Engine-independent statistics collected
test.t2 analyze status OK
SET optimizer_switch='rowid_filter=on';
SET optimizer_switch='index_merge_sort_intersection=off';
SELECT * FROM t1 JOIN t2 ON t1.f = t2.a WHERE t2.b >= 'j' AND t2.a != 5;
f pk a b
4 3 4 p
SET optimizer_switch='index_merge_sort_intersection=on';
SELECT * FROM t1 JOIN t2 ON t1.f = t2.a WHERE t2.b >= 'j' AND t2.a != 5;
f pk a b
4 3 4 p
DROP TABLE t1, t2;

View file

@ -476,3 +476,52 @@ DROP TABLE t1;
SET SESSION optimizer_switch='index_merge_sort_intersection=on';
SET SESSION optimizer_switch='rowid_filter=default';
--echo #
--echo # MDEV-38327 wrong result with index_merge_sort_intersection and rowid_filter=on
--echo #
--source include/have_sequence.inc
CREATE TABLE t1 (c int, b int, a int , d int, PRIMARY KEY (c), KEY ib (b), KEY iad (a,d));
INSERT INTO t1
SELECT seq + 1000000, FLOOR(seq / 5) % 1350 + 1000000, FLOOR(seq / 5) % 1350 , seq % 10 FROM seq_1_to_7000 ;
let $query=
select a, b, c from t1 where a=1000 and b=1001000;
eval explain $query;
eval $query;
set optimizer_switch='index_merge_sort_intersection=on';
eval explain $query;
eval $query;
analyze table t1;
eval explain $query;
eval $query;
drop table t1;
--echo ## MDEV-28878 case
CREATE TABLE t1 (f int);
INSERT INTO t1 VALUES (0),(4);
CREATE TABLE t2 (pk int, a int, b varchar(10), PRIMARY KEY (pk), KEY a (a), KEY b (b));
INSERT INTO t2 VALUES
(1,2,'v'),(2,3,'p'),(3,4,'p'),(4,2,'y'),(5,7,'q'),
(6,4,'a'),(7,1,'d'),(8,5,'a'),(9,5,'z'),(10,1,'t'),
(11,1,'y'),(12,5,'o'),(13,4,'a'),(14,5,'s'),(15,5,'m');
ANALYZE TABLE t1, t2 PERSISTENT FOR ALL;
SET optimizer_switch='rowid_filter=on'; # Default
SET optimizer_switch='index_merge_sort_intersection=off'; # Default
SELECT * FROM t1 JOIN t2 ON t1.f = t2.a WHERE t2.b >= 'j' AND t2.a != 5;
SET optimizer_switch='index_merge_sort_intersection=on';
SELECT * FROM t1 JOIN t2 ON t1.f = t2.a WHERE t2.b >= 'j' AND t2.a != 5;
DROP TABLE t1, t2;

View file

@ -979,6 +979,72 @@ f1 f4 f5
DROP TABLE t1;
SET SESSION optimizer_switch='index_merge_sort_intersection=on';
SET SESSION optimizer_switch='rowid_filter=default';
#
# MDEV-38327 wrong result with index_merge_sort_intersection and rowid_filter=on
#
CREATE TABLE t1 (c int, b int, a int , d int, PRIMARY KEY (c), KEY ib (b), KEY iad (a,d));
INSERT INTO t1
SELECT seq + 1000000, FLOOR(seq / 5) % 1350 + 1000000, FLOOR(seq / 5) % 1350 , seq % 10 FROM seq_1_to_7000 ;
explain select a, b, c from t1 where a=1000 and b=1001000;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge ib,iad ib,iad 5,5 NULL 1 Using sort_intersect(ib,iad); Using where
select a, b, c from t1 where a=1000 and b=1001000;
a b c
1000 1001000 1005000
1000 1001000 1005001
1000 1001000 1005002
1000 1001000 1005003
1000 1001000 1005004
set optimizer_switch='index_merge_sort_intersection=on';
explain select a, b, c from t1 where a=1000 and b=1001000;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge ib,iad ib,iad 5,5 NULL 1 Using sort_intersect(ib,iad); Using where
select a, b, c from t1 where a=1000 and b=1001000;
a b c
1000 1001000 1005000
1000 1001000 1005001
1000 1001000 1005002
1000 1001000 1005003
1000 1001000 1005004
analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
explain select a, b, c from t1 where a=1000 and b=1001000;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge ib,iad ib,iad 5,5 NULL 1 Using sort_intersect(ib,iad); Using where
select a, b, c from t1 where a=1000 and b=1001000;
a b c
1000 1001000 1005000
1000 1001000 1005001
1000 1001000 1005002
1000 1001000 1005003
1000 1001000 1005004
drop table t1;
## MDEV-28878 case
CREATE TABLE t1 (f int);
INSERT INTO t1 VALUES (0),(4);
CREATE TABLE t2 (pk int, a int, b varchar(10), PRIMARY KEY (pk), KEY a (a), KEY b (b));
INSERT INTO t2 VALUES
(1,2,'v'),(2,3,'p'),(3,4,'p'),(4,2,'y'),(5,7,'q'),
(6,4,'a'),(7,1,'d'),(8,5,'a'),(9,5,'z'),(10,1,'t'),
(11,1,'y'),(12,5,'o'),(13,4,'a'),(14,5,'s'),(15,5,'m');
ANALYZE TABLE t1, t2 PERSISTENT FOR ALL;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
test.t2 analyze status Engine-independent statistics collected
test.t2 analyze status OK
SET optimizer_switch='rowid_filter=on';
SET optimizer_switch='index_merge_sort_intersection=off';
SELECT * FROM t1 JOIN t2 ON t1.f = t2.a WHERE t2.b >= 'j' AND t2.a != 5;
f pk a b
4 3 4 p
SET optimizer_switch='index_merge_sort_intersection=on';
SELECT * FROM t1 JOIN t2 ON t1.f = t2.a WHERE t2.b >= 'j' AND t2.a != 5;
f pk a b
4 3 4 p
DROP TABLE t1, t2;
set global innodb_stats_persistent= @innodb_stats_persistent_save;
set global innodb_stats_persistent_sample_pages=
@innodb_stats_persistent_sample_pages_save;

View file

@ -14456,6 +14456,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
}
tab->type= JT_RANGE;
tab->use_quick=1;
if (is_index_merge(tab->quick->get_type()))
tab->clear_range_rowid_filter();
tab->ref.key= -1;
tab->ref.key_parts=0; // Don't use ref key.
join->best_positions[i].records_read= rows2double(tab->quick->records);