I have an index that filters 99% of the table i.e. ix_magic_composite
(for that query arguments).
When I add another or
filter it chooses the wrong index, i.e. fTS
even if I create an index that starts with that field it still choose the wrong index. Run times are 20s vs 3s to the better index. ix_magic_composite
index returns (initial filter) for both SQLs around 10 rows out of millions, while fTS
returns millions back.
Kind of clueless. It looks to me as the statistics aren't giving the engine the right picture with all those columns combined.
I simplified the table, it has a lot more columns and indexes.
SQL w/ good plan:
select *
from tblExample
where 1=1
and status = 'okay'
and textCol > ''
and insrBLN = 1
and (magic is NULL or magic = '')
and (itemId is NULL or itemId = '')
and fTS > '2020-01-01'
and fTS > '2020-01-01'
order by fTS
limit 50
+----+-------------+------------+------------+-------------+--------------------------------------------------+---------------------+---------+-------+---------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+-------------+--------------------------------------------------+---------------------+---------+-------+---------+----------+----------------------------------------------------+
| 1 | SIMPLE | tblExample | NULL | ref_or_null | textCol,status,textCol_4,ix_magic_composite,fTS | ix_magic_composite | 53 | const | 5892974 | 0.24 | Using index condition; Using where; Using filesort |
+----+-------------+------------+------------+-------------+--------------------------------------------------+---------------------+---------+-------+---------+----------+----------------------------------------------------+
SQL w/ bad plan:
select *
from tblExample
where 1=1
and status = 'okay'
and textCol > ''
and insrBLN = 1
and (magic is NULL or magic = '' or magic = 'retry')
and (itemId is NULL or itemId = '' or itemId = 'retry')
and fTS > '2020-01-01'
and fTS > '2020-01-01'
order by fTS
limit 50
+----+-------------+------------+------------+-------+-------------------------------------------------+---------+---------+------+---------+----------+------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+-------+-------------------------------------------------+---------+---------+------+---------+----------+------------------------------------+
| 1 | SIMPLE | tblExample | NULL | range | textCol,status,textCol_4,ix_magic_composite,fTS | fTS | 5 | NULL | 6271587 | 0.18 | Using index condition; Using where |
+----+-------------+------------+------------+-------+----------------------------------------- ----+---------+---------+------+---------+----------+------------------------------------+
Table:
CREATE TABLE `tblExample` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`fTS` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`status` varchar(50) NOT NULL DEFAULT 'new',
`textCol` varchar(50) DEFAULT NULL,
`insrBLN` tinyint(4) NOT NULL DEFAULT '0',
`itemId` varchar(50) DEFAULT NULL ,
`magic` varchar(50) DEFAULT NULL ,
PRIMARY KEY (`id`),
KEY `ix_magic_composite` (`itemId`,`magic`,`fTS`,`insrBLN`),
KEY `fTS` (`fTS`)
) ENGINE=InnoDB AUTO_INCREMENT=14391289 DEFAULT CHARSET=latin1
EDIT
We have refactor the code so the query looks like:
select *
from tblExample
where 1=1
and status = 'okay'
and textCol > ''
and insrBLN = 1
and (retry = '' or (retry='retry' and retryDT < now() - interval 1 day))
and fTS > '2020-01-01'
order by fTS
limit 50
The issue was NOT sorted (also tried different columns order in the index). It looks like it chooses the right index only if I remove the order by.