MySQL - 范围条件和排序依据

MySQL - RANGE CONDITION and ORDER BY

"High Performance MySQL"书中说,

The ORDER BY clause also has the same limitation as lookup queries: it needs to form a leftmost prefix of the index. In all other cases, MySQL uses a filesort.

这里有一个 table 有一个索引 (rental_date, inventory_id, customer_id):

CREATE TABLE rental (
...
PRIMARY KEY (rental_id),
UNIQUE KEY rental_date (rental_date,inventory_id,customer_id),
KEY idx_fk_inventory_id (inventory_id),
KEY idx_fk_customer_id (customer_id),
KEY idx_fk_staff_id (staff_id),
...
);

MySQL uses the rental_date index to order the following query, as you can see from the lack of a filesort in EXPLAIN:

> mysql> EXPLAIN SELECT
> rental_id, staff_id FROM sakila.rental
> -> WHERE rental_date = '2005-05-25'
> -> ORDER BY inventory_id, customer_id\G
> *************************** 1. row *************************** 
> type: ref 
> possible_keys: rental_date 
> key: rental_date 
> rows: 1 
> Extra: Using where 

This works, even though the ORDER BY clause isn’t itself a leftmost prefix of the index, because we specified an equality condition for the first column in the index.

This query has range condition on the first column, so MySQL doesn't use the rest of index:

EXPLAIN 
SELECT `rental_id`, `staff_id` FROM `sakila`.`rental`
WHERE `rental_date` > '2005-05-25'
ORDER BY `inventory_id`, `customer_id`;
*************************** 1. row *************************** 
...
key: NULL Extra: Using where; using filesort
...

问题:为什么查询第一列有范围条件,MySQL没有使用索引?

匹配 'rental_date' > '2005-05-25' 的第一个位置将使用 B 树索引找到。然后 MySQL 可以按顺序扫描子节点(inventory_id,customer_id),我想。有什么问题吗?

假设索引是这样的:

rental_date, inventory_id, customer_id
======================================
...
2005-05-25, 10, 10
2005-05-25, 20, 20
2005-05-25, 30, 30
2005-05-26, 20, 20
2005-05-26, 40, 40
2005-05-27, 10, 10
2005-05-27, 30, 30
...

在第一个查询中 mysql 使用索引查找第一个条目“2005-05-25”。由于 rental_date 是索引的第一个字段,因此相同日期值的其他字段(inventory_idcustomer_id)按排序顺序排列。

但是在第二个查询中想象一下 2005-05-262005-05-27 会发生什么。突然,inventory_idcustomer_id 没有排序。它们仅针对特定的 rental_date 值进行排序。所以 mysql 最后必须对它们进行排序。