I'm trying to get a query containing a range and ORDER BY ... DESC to use an index.
The index is used if I remove the ORDER BY and just use the range.
The index is also used if I remove the range and just use the ORDER BY.
Table:
CREATE TABLE `messages` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`service` varchar(260) COLLATE utf8mb4_unicode_ci NOT NULL,
`time` datetime NOT NULL,
`country` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
`city` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`country_code` char(2) COLLATE utf8mb4_unicode_ci NOT NULL,
`issue` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`latitude` double DEFAULT NULL,
`longitude` double DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `service_time_idx` (`service`,`time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
Query with range and ORDER BY (Not using index):
MariaDB [m]> explain select service, time, country, city, country_code,
issue, latitude, longitude
from messages
where service = 'myservice'
and time BETWEEN DATE_SUB( NOW() , INTERVAL 24 HOUR ) AND NOW()
order by time desc;
+------+-------------+---------------------------+-------+------------------+------------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------------------------+-------+------------------+------------------+---------+------+------+-------------+
| 1 | SIMPLE | messages | range | service_time_idx | service_time_idx | 1047 | NULL | 1 | Using where |
+------+-------------+---------------------------+-------+------------------+------------------+---------+------+------+-------------+
Query just using range (using index).
MariaDB [m]> explain select service, time, country, city, country_code,
issue, latitude, longitude
from messages
where service = 'myservice'
and time BETWEEN DATE_SUB( NOW() , INTERVAL 24 HOUR ) AND NOW();
+------+-------------+---------------------------+-------+------------------+------------------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------------------------+-------+------------------+------------------+---------+------+------+-----------------------+
| 1 | SIMPLE | messages | range | service_time_idx | service_time_idx | 1047 | NULL | 1 | Using index condition |
+------+-------------+---------------------------+-------+------------------+------------------+---------+------+------+-----------------------+
1 row in set (0.004 sec)
Query just using ORDER BY (using index):
MariaDB [m]> explain select service, time, country, city, country_code, issue, latitude, longitude
from messages
where service = 'myservice'
and time = '2020-10-03 09:51:25'
order by time desc;
+------+-------------+---------------------------+------+------------------+------------------+---------+-------------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------------------------+------+------------------+------------------+---------+-------------+------+-----------------------+
| 1 | SIMPLE | messages | ref | service_time_idx | service_time_idx | 1047 | const,const | 1 | Using index condition |
+------+-------------+---------------------------+------+------------------+------------------+---------+-------------+------+-----------------------+
1 row in set, 1 warning (0.001 sec)
Oddly, I can get the query to work with both the range and ORDER BYif I only select on the service and time columns:
MariaDB [m]> explain select service, time from messages
where service = 'myservice'
and time BETWEEN DATE_SUB( NOW() , INTERVAL 24 HOUR ) AND NOW()
order by time desc;
+------+-------------+---------------------------+------+------------------+------------------+---------+-------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------------------------+------+------------------+------------------+---------+-------+------+--------------------------+
| 1 | SIMPLE | messages | ref | service_time_idx | service_time_idx | 1042 | const | 1 | Using where; Using index |
+------+-------------+---------------------------+------+------------------+------------------+---------+-------+------+--------------------------+
1 row in set (0.002 sec)
MariaDB [m]> EXPLAIN FORMAT=JSON select service, time, country, city, country_code,
issue, latitude, longitude
from messages
where service = 'myservice'
and time BETWEEN DATE_SUB( NOW() , INTERVAL 24 HOUR ) AND NOW()
order by time desc;
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "messages",
"access_type": "range",
"possible_keys": ["service_time_idx"],
"key": "service_time_idx",
"key_length": "1047",
"used_key_parts": ["service", "time"],
"rows": 1,
"filtered": 100,
"attached_condition": "messages.service = 'myservice' and messages.`time` between <cache>(current_timestamp() - interval 24 hour) and <cache>(current_timestamp())"
}
}
}
How can I get the first query above to use the index?
Obviously I can write the query a different way if I need to.