开发者

MySQL index misses

I have a query that looks like the following:

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

since expires_at is i开发者_如何学Cndexed, the query hits the index no problem. however the following query:

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

the index never gets hit.

both expires_at and some_id are indexed.

is my index not properly created?


This query:

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

can be satisfied by the index only, without referring to the table itself. You may see it from the using index in the plan.

This query:

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

needs to look into the table to find the value of some_id.

Since the table lookup is quite an expensive thing, it is more efficient to use the table scan and filter the records.

If you had a composite index on expires_at, some_id, the query would probably use the index both for ranging on expires_at and filtering on some_id.

SQL Server even offers a feature known as included fields for this. This command

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

would create an index on expires_at which would additionally store some_id in the leaf entires (without overhead of sorting).

MySQL, unfortunately, does not support it.


Probably what's happening is that for the first query, the index can be used to count the rows satisfying the WHERE clause. In other words, the query would result in a table scan, but happily all the columns involved in the WHERE condition are in an index, so the index is scanned instead.

In the second query though, there's no single index that contains all the columns in the WHERE clause. So MySQL resorts to a full table scan. In the case of the first query, it was using your index, but not to find the rows to check - in the special case of a COUNT() query, it could use the index to count rows. It was doing the equivalent of a table scan, but on the index instead of the table.


1) It seems you have two single-column indices. You can try to create a multi-column index.

For a detailed explanation why this is different than multiple single column indices, see the following: http://www.mysqlfaqs.net/mysql-faqs/Indexes/When-does-multi-column-index-come-into-use-in-MySQL

2) Do you have a B-tree index on the expires_at column? Since you are doing a range query (<), that might give better performance.

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

Best of luck!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜