MySQL可以使用ORDER BY在RANGE QUERY中使用索引吗?

时间:2010-11-03 01:50:58

标签: mysql indexing query-optimization sql-order-by

我有一个MySQL表:

CREATE TABLE mytable (
     id INT NOT NULL AUTO_INCREMENT,
     other_id INT NOT NULL,
     expiration_datetime DATETIME,
     score INT,
     PRIMARY KEY (id)
) 

我需要以下列形式运行查询:

SELECT * FROM mytable
WHERE other_id=1 AND expiration_datetime > NOW() 
ORDER BY score LIMIT 10

如果我将此索引添加到mytable:

CREATE INDEX order_by_index
ON mytable ( other_id, expiration_datetime, score);

MySQL能否在上面的查询中使用整个order_by_index

它似乎应该可以,但是根据MySQL的documentation:“即使ORDER BY与索引完全不匹配,也可以使用索引,只要全部索引的未使用部分和所有额外的ORDER BY列是WHERE子句中的常量。

以上段落似乎表明索引仅用于常量查询,而我的是范围查询。

有人可以澄清在这种情况下是否会使用索引?如果没有,我可以用任何方式强制使用索引吗?

感谢。

3 个答案:

答案 0 :(得分:8)

MySQL将使用索引来满足where子句,并将使用filesort来对结果进行排序。

它不能使用order by作为order by,因为你没有将expiration_datetime与一个常量进行比较。因此,返回的行并不总是在索引中都有一个公共前缀,因此索引不能用于排序。

例如,考虑一下包含4个索引记录的样本集:

a) [1,'2010-11-03 12:00',1]
b) [1,'2010-11-03 12:00',3]
c) [1,'2010-11-03 13:00',2]
d) [2,'2010-11-03 12:00',1]

如果我在2010-11-03 11:00运行您的查询,它将返回索引中不连续的行a,c,d。因此,MySQL需要执行额外的传递来对结果进行排序,并且在这种情况下不能使用索引。

答案 1 :(得分:7)

  

有人可以澄清在这种情况下是否会使用索引?如果没有,我可以用任何方式强制使用索引吗?

您有过滤条件的范围且ORDER BY与范围不匹配。

这些条件无法通过单一索引提供。

要选择要创建的索引,您需要运行这些查询

SELECT  COUNT(*)
FROM    mytable
WHERE   other_id = 1
        AND (score, id) <
        (
        SELECT  score, id
        FROM    mytable
        WHERE   other_id = 1
                AND expiration_datetime > NOW() 
        ORDER BY
                score, id
        LIMIT 10
        )

SELECT  COUNT(*)
FROM    mytable
WHERE   other_id = 1
        AND expiration_datetime >= NOW()

并比较他们的输出。

如果第二个查询产生与第一个查询大致相同或更多的值,那么您应该使用(other_id, score)上的索引(并让它过滤expiration_datetime)。

如果第二个查询产生的值远远低于第一个查询,则应使用(other_id, expiration_datetime)上的索引(并让它在score上排序)。

这篇文章可能对你很有意思:

答案 2 :(得分:3)

听起来您已经检查了文档并设置了索引。使用EXPLAIN并查看...

EXPLAIN SELECT * FROM mytable
WHERE other_id=1 AND expiration_datetime > NOW() 
ORDER BY score LIMIT 10