MySQL索引未命中

时间:2011-05-05 12:45:31

标签: mysql indexing

我有一个如下所示的查询:

select count(*) from `foo` where expires_at < now()”

因为expires_at被索引,查询命中索引没问题。但是以下查询:

select count(*) from `foo` where expires_at < now() and some_id != 5

索引永远不会被击中。

expires_at和some_id都被编入索引。

我的索引没有正确创建?

3 个答案:

答案 0 :(得分:1)

此查询:

SELECT  COUNT(*)
FROM    foo
WHERE   expires_at < NOW()

只能通过索引来满足,而不需要引用表本身。您可以从计划中的using index看到它。

此查询:

SELECT  COUNT(*)
FROM    foo
WHERE   expires_at < NOW()
        AND some_id <> 5

需要查看表格以查找some_id的值。

由于表查找非常昂贵,因此使用表扫描并过滤记录会更有效。

如果您在expires_at, some_id上有一个综合索引,则该查询可能会使用该索引进行expires_at上的范围调整和some_id上的过滤。

SQL Server甚至为此提供了一项名为included fields的功能。这个命令

CREATE INDEX ix_foo_expires__someid ON foo (expires_at) INCLUDE (some_id)

将在expires_at上创建一个索引,该索引还会在叶子中存储some_id(没有排序开销)。

遗憾的是,

MySQL不支持它。

答案 1 :(得分:0)

可能发生的事情是,对于第一个查询,索引可用于计算满足WHERE子句的行。换句话说,查询导致表扫描,但很高兴WHERE条件中涉及的所有列都在索引中,因此会扫描索引。

在第二个查询中,没有一个索引包含WHERE子句中的所有列。所以MySQL采用全表扫描。在第一个查询的情况下,它使用您的索引,但没有找到要检查的行 - 在COUNT()查询的特殊情况下,它可以使用索引来计算行。它相当于表扫描,但是在索引而不是表上。

答案 2 :(得分:0)

1)看来你有两个单列索引。您可以尝试创建多列索引。

有关为何与多个单列索引不同的详细说明,请参阅以下内容: http://www.mysqlfaqs.net/mysql-faqs/Indexes/When-does-multi-column-index-come-into-use-in-MySQL

2)expires_at列上有B树索引吗?由于您正在进行范围查询(&lt;),因此可能会提供更好的性能。

http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html

祝你好运!