我有一个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子句中的常量。“
以上段落似乎表明索引仅用于常量查询,而我的是范围查询。
有人可以澄清在这种情况下是否会使用索引?如果没有,我可以用任何方式强制使用索引吗?
感谢。
答案 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