为什么MySQL不使用索引?

时间:2013-03-18 02:54:36

标签: mysql sql database

我们的MySQL(Percona Server)数据库有一个1000万行的大表,有很多慢查询长度超过40秒这样:

  SELECT col1, Seller, col3, col4, Id, col5  
    FROM table1 
   WHERE Seller = 346761 
     AND col1 IN (2, 3, 4) 
     AND col3 = 1  
     AND col4 NOT IN (5,6,7)  
ORDER BY Id DESC 
   LIMIT 0, 20;

我在Sellercol1col3col4上创建了索引。这些索引是单独的,而不是多列索引(AKA覆盖索引)。 Id是主键。

EXPLAIN显示MySQL使用主键作为索引查询此sql,而不是关于卖家的索引。

+----+-------------+------------------+-------+--------------------+---------+---------+------+------+-------------+
| id | select_type | table            | type  | possible_keys      | key     | key_len | ref  | rows | Extra       |
+----+-------------+------------------+-------+--------------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | trans_audit_list | index | Seller,AuditStatus | PRIMARY | 8       | NULL | 1483 | Using where | 
+----+-------------+------------------+-------+--------------------+---------+---------+------+------+-------------+

当我force index (Seller)时,它非常快,0.7秒。

我发现如果不使用limit语句,这个查询将使用Seller索引,会非常快。 为什么MySQL没有在Seller上使用带有限制语句的索引?

3 个答案:

答案 0 :(得分:1)

正如您所遇到的那样,拥有索引并不意味着它将被使用。这适用于每个数据库 - 索引选择取决于查询优化器。正如您所尝试的那样,强制索引并不意味着您将获得最快的结果。

之后,查询缓存可能无法帮助您 - 可以缓存查询计划,因此甚至不会考虑索引。

MySQL每个语句只使用一个索引,所以覆盖索引(多列)是个好主意,但你必须测试它才能确定。

答案 1 :(得分:1)

ORDER BY DESC + LIMIT条款is a common problematic situation for mysql的优化程序中添加了多个可能的索引情况,强制索引的极少数情况之一实际上可能是合法的。

请注意,您的条款IN (...)是优化程序的额外麻烦。

如果您确实不需要,我建议您按ID ASC而不是DESC订购,以便引擎可以使用主键排序的好处,即ASC直到进一步实施。

答案 2 :(得分:1)

[Seller]上的非群集索引可能包含太多碎片,并且您的统计信息可能已过期,然后查询优化程序可能无法选择最佳查询计划。如果您还可以为此查询创建覆盖索引(如果用户经常使用此查询),那么检查碎片,更新统计信息或重新构建卖家的非群集索引,这是值得的。创建覆盖索引时,请确保订单是最终用户最常使用的。与您的查询一样,覆盖索引应该在[seller-> col1-> col3-> col4]