From f17beec0c4489ed84478a4a24c2b8fd72db1c651 Mon Sep 17 00:00:00 2001 From: bsrikanth-mariadb Date: Fri, 26 Jun 2026 16:48:14 +0530 Subject: [PATCH] MDEV-39942: use actual_rec_per_key in loose scan sj optimization While performing loose scan semi-join optimization in Loose_scan_opt::check_ref_access_part1() [opt_subselect.h], the filtered value in the explain plan was in-consistent for a table with index when same data was inserted using "insert into t1 values()...", and "insert into t1 select * from t2". This is noticed when rec_per_key[] was used to get the number of records during optimization. However, when actual_rec_per_key() is used to get the number of records, we don't notice this discrepancy. This PR changes the rec_per_key[] usage to actual_rec_per_key() in the method Loose_scan_opt::check_ref_access_part1() [opt_subselect.h] --- mysql-test/main/subselect_sj_mat.result | 10 +++++----- sql/opt_subselect.h | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/mysql-test/main/subselect_sj_mat.result b/mysql-test/main/subselect_sj_mat.result index 215314e398b1b..cc382e53b3b1f 100644 --- a/mysql-test/main/subselect_sj_mat.result +++ b/mysql-test/main/subselect_sj_mat.result @@ -107,7 +107,7 @@ a1 a2 explain extended select * from t1i where a1 in (select b1 from t2i where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t2i index it2i1,it2i3 it2i1 # NULL 5 50.00 Using where; Using index; LooseScan +1 PRIMARY t2i index it2i1,it2i3 it2i1 # NULL 5 100.00 Using where; Using index; LooseScan 1 PRIMARY t1i ref _it1_idx _it1_idx # _ref_ 1 20.00 Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` semi join (`test`.`t2i`) where `test`.`t1i`.`a1` = `test`.`t2i`.`b1` and `test`.`t2i`.`b1` > '0' @@ -130,7 +130,7 @@ a1 a2 explain extended select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t2i index it2i1,it2i2,it2i3 it2i3 # NULL 5 50.00 Using where; Using index; LooseScan +1 PRIMARY t2i index it2i1,it2i2,it2i3 it2i3 # NULL 5 100.00 Using where; Using index; LooseScan 1 PRIMARY t1i ref _it1_idx _it1_idx # _ref_ 1 20.00 Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` semi join (`test`.`t2i`) where `test`.`t1i`.`a1` = `test`.`t2i`.`b1` and `test`.`t1i`.`a2` = `test`.`t2i`.`b2` and `test`.`t2i`.`b1` > '0' @@ -276,7 +276,7 @@ a1 a2 explain extended select * from t1i where (a1, a2) in (select b1, b2 from t2i order by b1, b2); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t2i index it2i1,it2i2,it2i3 it2i3 18 NULL 5 50.00 Using where; Using index; LooseScan +1 PRIMARY t2i index it2i1,it2i2,it2i3 it2i3 18 NULL 5 100.00 Using where; Using index; LooseScan 1 PRIMARY t1i ref it1i1,it1i2,it1i3 it1i3 18 test.t2i.b1,test.t2i.b2 1 20.00 Using index Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` semi join (`test`.`t2i`) where `test`.`t1i`.`a1` = `test`.`t2i`.`b1` and `test`.`t1i`.`a2` = `test`.`t2i`.`b2` @@ -348,7 +348,7 @@ where (a1, a2) in (select b1, b2 from t2i where b1 > '0') and (a1, a2) in (select c1, c2 from t3i where (c1, c2) in (select b1, b2 from t2i where b2 > '0')); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t2i index it2i1,it2i2,it2i3 # # # 5 50.00 # +1 PRIMARY t2i index it2i1,it2i2,it2i3 # # # 5 100.00 # 1 PRIMARY t1i ref it1i1,it1i2,it1i3 # # # 1 20.00 # 1 PRIMARY t3i ref it3i1,it3i2,it3i3 # # # 1 100.00 # 1 PRIMARY t2i ref it2i1,it2i2,it2i3 # # # 1 60.00 # @@ -432,7 +432,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL # # # 4 15.00 # 4 MATERIALIZED t3 ALL NULL # # # 4 100.00 # 3 MATERIALIZED t3 ALL NULL # # # 4 100.00 # -7 UNION t2i index it2i1,it2i2,it2i3 # # # 5 50.00 # +7 UNION t2i index it2i1,it2i2,it2i3 # # # 5 100.00 # 7 UNION t1i ref it1i1,it1i2,it1i3 # # # 1 20.00 # 7 UNION t3i ref it3i1,it3i2,it3i3 # # # 1 100.00 # 7 UNION t2i ref it2i1,it2i2,it2i3 # # # 1 60.00 # diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h index 7c0e16b08e140..f0234250f8bbc 100644 --- a/sql/opt_subselect.h +++ b/sql/opt_subselect.h @@ -244,7 +244,8 @@ class Loose_scan_opt scan will produce more distinct records than it actually will) */ ulong rpc; - if ((rpc= s->table->key_info[key].rec_per_key[max_loose_keypart])) + if ((rpc= (ulong) s->table->key_info[key].actual_rec_per_key( + max_loose_keypart))) records= records / rpc; // TODO: previous version also did /2