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

Con*_*ion 9 mysql indexing sql-order-by query-optimization

我有一个MySQL表:

CREATE TABLE mytable (
     id INT NOT NULL AUTO_INCREMENT,
     other_id INT NOT NULL,
     expiration_datetime DATETIME,
     score INT,
     PRIMARY KEY (id)
) 
Run Code Online (Sandbox Code Playgroud)

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

SELECT * FROM mytable
WHERE other_id=1 AND expiration_datetime > NOW() 
ORDER BY score LIMIT 10
Run Code Online (Sandbox Code Playgroud)

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

CREATE INDEX order_by_index
ON mytable ( other_id, expiration_datetime, score);
Run Code Online (Sandbox Code Playgroud)

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

现在看来似乎应该是可以的,但后来根据MySQL的文档:" 该指数还可以用来即使ORDER BY不索引完全一致,只要所有索引的未使用部分和所有的额外ORDER BY列是WHERE子句中的常量. "

上面的段落似乎表明索引只能用于常量查询,而我的是范围查询.

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

谢谢.

Ike*_*ker 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]
Run Code Online (Sandbox Code Playgroud)

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


Qua*_*noi 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
        )
Run Code Online (Sandbox Code Playgroud)

SELECT  COUNT(*)
FROM    mytable
WHERE   other_id = 1
        AND expiration_datetime >= NOW()
Run Code Online (Sandbox Code Playgroud)

并比较他们的输出.

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

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

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