我有一个如下所示的查询:
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都被编入索引。
我的索引没有正确创建?
答案 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
祝你好运!