I have the following query:
select *
from test_table
where app_id = 521
and is_deleted=0
and category in (7650)
AND created_timestamp >= '2020-07-28 18:19:26'
AND created_timestamp <= '2020-08-04 18:19:26'
ORDER BY created_timestamp desc
limit 30
All four fields, app_id, is_deleted, category and created_timestamp are indexed. However, the cardinality of app_id and is_deleted are very small (3 each).
category field is fairly distributed, but created_timestamp seems like a very good index choice for this query.
However, MySQL is not using the created_timestamp index and is in turn taking 4 seconds to return. If I force MySQL to use the created_timestamp index using USE INDEX (created_timestamp), it returns in 40ms.
I checked the output of explain command to see why that's happening, an found that MySQL is performing the query with the following params:
Automatic index decision, takes > 4s
type: index_merge
key: category,app_id,is_deleted
rows: 10250
filtered: 0.36
Using intersect(category,app_id,is_deleted); Using where; Using filesort
Force index usage:
Use index created_timestamp, takes < 50ms
type: range
key: created_timestamp
rows: 47000
filtered: 0.50
Using index condition; Using where; Backward index scan
MySQL probably decides that lesser number of rows to scan is better, and that makes sense also, but then why does it take forever for the query to return in that case? How can I fix this query?
Using intersectis like doing three queries, to find several subsets of the table, finding rows that exist in all three subsets. You should consider defining a multi-column index on(app_id, is_deleted, created_timestamp, category)in that order.INhad multiple values, I might agree with your ordering. When there is only one id, it will be optimized as=, at which point, it is distinctly better to putcategorybefore the date range.created_timestampfirst eliminates the filesort. The fourth column can't be searched as a SQL-layer lookup either way, but it can at least be filtered by InnoDB index condition pushdown.category IN (7650), which is optimized identically tocategory = 7650, it will get pastcategory.