Bug #117619 MySQL indexes in MyISAM tables not behave as expected.
Submitted: 5 Mar 0:14 Modified: 5 Mar 5:14
Reporter: Haoqiao Song Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S2 (Serious)
Version:8.*, 8.0.41, 8.0.44 OS:Any
Assigned to: CPU Architecture:Any

[5 Mar 0:14] Haoqiao Song
Description:
Create a temporary table on the replica (which is read only), it’s being created as MyISAM table. Let’s say the table has 4 varchar fields. 

Inserted multiple rows with random values. 

Run SELECT and trying to search all of the fields for a value, the query response is as expected. No mater in which of the fields, the value is matched.

Created 4 indexes for each of those fields. 

*** The BUG happens ***

RunSELECT for a value in the table, a match is only returned if I am querying a value contained in the FIRST field. If I SELECT for a value in any of the 3 other fields, no results are returned. 

When I do EXPLAIN for this SELECT, it shows "Using union” for indexing.

When I switch the “index_merge_union” flag to “off” which is found in system variable “optimizer_switch”, any SELECT query returns correct results.

How to repeat:
Create the temp table

use db1;
create temporary table stat_tmp (
    f1 varchar(15) NOT NULL DEFAULT '',
    f2 varchar(15) NOT NULL DEFAULT '',
    f3 varchar(15) NOT NULL DEFAULT '',
    f4 varchar(15) NOT NULL DEFAULT ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

Insert test records

insert into stat_tmp values ('1', '0', '0', '0');
insert into stat_tmp values ('1', '0', '1', '0');
insert into stat_tmp values ('0', '0', '0', '2');
insert into stat_tmp values ('0', '0', '1', '0');
insert into stat_tmp values ('0', '3', '2', '0');

Test queries

select * from stat_tmp where f1 = '1' or f2 = '1' or f3 = '1' or f4 = '1';
select * from stat_tmp where f1 = '3' or f2 = '3' or f3 = '3' or f4 = '3';

Created indexes

alter table stat_tmp add index (f1), add index (f2), add index (f3), add index (f4);

Run the same queries

select * from stat_tmp where f1 = '1' or f2 = '1' or f3 = '1' or f4 = '1';
returned the same set of records
select * from stat_tmp where f1 = '3' or f2 = '3' or f3 = '3' or f4 = '3';
return nothing

>Turn off index_merge_union

SET SESSION optimizer_switch = 'index_merge_union=off';
The results back to be expected.

This only happened when the temp table is in MyISAM and the data type are char ().
```

One iteration:
==============

```
mysql> use db1;
Database changed

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.41    |
+-----------+
1 row in set (0.00 sec)

mysql> create temporary table stat_tmp (
    -> f1 varchar(15) NOT NULL DEFAULT '',
    -> f2 varchar(15) NOT NULL DEFAULT '',
    -> f3 varchar(15) NOT NULL DEFAULT '',
    -> f4 varchar(15) NOT NULL DEFAULT ''
    -> ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into stat_tmp values ('1', '0', '0', '0');
Query OK, 1 row affected (0.00 sec)

mysql> insert into stat_tmp values ('1', '0', '1', '0');
Query OK, 1 row affected (0.00 sec)

mysql> insert into stat_tmp values ('0', '0', '0', '2');
Query OK, 1 row affected (0.00 sec)

mysql> insert into stat_tmp values ('0', '0', '1', '0');
Query OK, 1 row affected (0.00 sec)

mysql> insert into stat_tmp values ('0', '3', '2', '0');
Query OK, 1 row affected (0.00 sec)

mysql> select * from stat_tmp where f1 = '1' or f2 = '1' or f3 = '1' or f4 = '1';
+----+----+----+----+
| f1 | f2 | f3 | f4 |
+----+----+----+----+
| 1  | 0  | 0  | 0  |
| 1  | 0  | 1  | 0  |
| 0  | 0  | 1  | 0  |
+----+----+----+----+
3 rows in set (0.00 sec)

mysql> select * from stat_tmp where f1 = '3' or f2 = '3' or f3 = '3' or f4 = '3';
+----+----+----+----+
| f1 | f2 | f3 | f4 |
+----+----+----+----+
| 0  | 3  | 2  | 0  |
+----+----+----+----+
1 row in set (0.00 sec)

mysql> alter table stat_tmp add index (f1), add index (f2), add index (f3), add index (f4);

Query OK, 5 rows affected (0.00 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> select * from stat_tmp where 1 and (f1 = '1' or f2 = '1' or f3 = '1' or f4 = '1');

+----+----+----+----+
| f1 | f2 | f3 | f4 |
+----+----+----+----+
| 1  | 0  | 0  | 0  |
| 1  | 0  | 1  | 0  |
| 0  | 0  | 1  | 0  |
+----+----+----+----+
3 rows in set (0.00 sec)

mysql> select * from stat_tmp where f1 = '3' or f2 = '3' or f3 = '3' or f4 = '3';

Empty set (0.00 sec)

mysql> SET SESSION optimizer_switch = 'index_merge_union=off';
Query OK, 0 rows affected (0.00 sec)

mysql> select * from stat_tmp where f1 = '3' or f2 = '3' or f3 = '3' or f4 = '3';
+----+----+----+----+
| f1 | f2 | f3 | f4 |
+----+----+----+----+
| 0  | 3  | 2  | 0  |
+----+----+----+----+
1 row in set (0.00 sec)
```
[5 Mar 5:14] MySQL Verification Team
Hello Haoqiao Song,

Thank you for the report and test case.
Verified as described.

regards,
Umesh