I have this table (simplified version)
create table completions ( id int(11) not null auto_increment, completed_at datetime default null, is_mongo_synced tinyint(1) default '0', primary key (id), key index_completions_on_completed_at_and_is_mongo_synced_and_id (completed_at,is_mongo_synced,id), ) engine=innodb auto_increment=4785424 default charset=utf8 collate=utf8_unicode_ci;
The size:
select count(*) from completions;
Now I am trying to execute this query:
select completions.* from completions where (completed_at is not null) and completions.is_mongo_synced = 0 order by completions.id asc limit 10;
And it takes 9mins .
I see that no index is used, explain extend returns this:
id: 1 select_type: SIMPLE table: completions type: index possible_keys: index_completions_on_completed_at_and_is_mongo_synced_and_id key: PRIMARY key_len: 4 ref: NULL rows: 20 filtered: 11616415.00 Extra: Using where
If I force the index:
select completions.* from completions force index(index_completions_on_completed_at_and_is_mongo_synced_and_id) where (completed_at is not null) and completions.is_mongo_synced = 0 order by completions.id asc limit 10;
It takes 1.22 s , which is much better. explain extend returns:
id: 1 select_type: SIMPLE table: completions type: range possible_keys: index_completions_on_completed_at_and_is_mongo_synced_and_id key: index_completions_on_completed_at_and_is_mongo_synced_and_id key_len: 6 ref: null rows: 2323334 filtered: 100 Extra: Using index condition; Using filesort
Now, if I judge the completions.id request as follows:
select completions.* from completions force index(index_completions_on_completed_at_and_is_mongo_synced_and_id) where (completed_at is not null) and completions.is_mongo_synced = 0 and completions.id > 2000000 order by completions.id asc limit 10;
It takes 1.31 s , still good. explain extend returns:
id: 1 select_type: SIMPLE table: completions type: range possible_keys: index_completions_on_completed_at_and_is_mongo_synced_and_id key: index_completions_on_completed_at_and_is_mongo_synced_and_id key_len: 6 ref: null rows: 2323407 filtered: 100 Extra: Using index condition; Using filesort
The fact is that if for the last query I do not force the index:
select completions.* from completions where (completed_at is not null) and completions.is_mongo_synced = 0 and completions.id > 2000000 order by completions.id asc limit 10;
It takes 85 ms , check that it is ms , not s . explain extend returns:
id: 1 select_type: SIMPLE table: completions type: range possible_keys: PRIMARYindex_completions_on_completed_at_and_is_mongo_synced_and_id key: PRIMARY key_len: 4 ref: null rows: 2323451 filtered: 100 Extra: Using where
Not only does this annoy me, but the fact that the performance of the last request is highly dependent on small changes in the number of filters:
select completions.* from completions where (completed_at is not null) and completions.is_mongo_synced = 0 and completions.id > 1600000 order by completions.id asc limit 10;
13s required
Things I don't understand:
- Why is lower query A faster than query B when query B involves using a more accurate index: c
Request A:
select completions.* from completions where (completed_at is not null) and completions.is_mongo_synced = 0 and completions.id > 2000000 order by completions.id asc limit 10;
85ms
Request B:
select completions.* from completions force index(index_completions_on_completed_at_and_is_mongo_synced_and_id) where (completed_at is not null) and completions.is_mongo_synced = 0 and completions.id > 2000000 order by completions.id asc limit 10;
1.31s
2. Why is there such a difference in the following queries:
Request A:
select completions.* from completions where (completed_at is not null) and completions.is_mongo_synced = 0 and completions.id > 2000000 order by completions.id asc limit 10;
85ms
Request B:
select completions.* from completions where (completed_at is not null) and completions.is_mongo_synced = 0 and completions.id > 1600000 order by completions.id asc limit 10;
13s
3. Why MySQL does not automatically use the index for the following query:
Pointer:
key index_completions_on_completed_at_and_is_mongo_synced_and_id (completed_at,is_mongo_synced,id),
Query:
select completions.* from completions force index(index_completions_on_completed_at_and_is_mongo_synced_and_id) where (completed_at is not null) and completions.is_mongo_synced = 0 and completions.id > 2000000 order by completions.id asc limit 10;
Update
Some more data requested in the comments
Number of rows based on
is_mongo_synced values
select completions.is_mongo_synced, count(*) from completions group by completions.is_mongo_synced;
Result:
[ { "is_mongo_synced":0, "count(*)":2731921 }, { "is_mongo_synced":1, "count(*)":2087869 } ]
Requests without
order by select completions.* from completions where (completed_at is not null) and completions.is_mongo_synced = 0 and completions.id > 2000000 limit 10;
544ms
select completions.* from completions force index(index_completions_on_completed_at_and_is_mongo_synced_and_id) where (completed_at is not null) and completions.is_mongo_synced = 0 and completions.id > 2000000 limit 10;
314ms
But, in any case, I need an order, because I look at a batch batch of packages.