为啥 MySQL 不使用索引?

Posted

技术标签:

【中文标题】为啥 MySQL 不使用索引?【英文标题】:Why Does MySQL not use an index?为什么 MySQL 不使用索引? 【发布时间】:2013-03-18 02:54:35 【问题描述】:

我们的 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 上的索引?

【问题讨论】:

您应该对查询运行 EXPLAIN 并发布结果。 您需要向我们展示表和索引定义。 诊断慢查询需要完整的表和索引定义,而不仅仅是描述或解释。也许您的表格定义不佳。也许索引没有正确创建。也许您认为您在该列上没有索引。没有看到表和索引定义,我们无法判断。如果您知道如何处理EXPLAIN 或获取执行计划,请将结果也放入问题中。 谢谢,我已经在我的问题中发布了 EXPLAIN 结果。 【参考方案1】:

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

另请注意,您的子句 IN (...) 给优化器带来了额外的麻烦。

如果您真的不需要它,我建议通过 id ASC 而不是 DESC 进行排序,以便引擎可以利用主键排序的好处,即 ASC,直到进一步实施。

【讨论】:

【参考方案2】:

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

因此,查询缓存可能对您没有帮助 - 查询计划可能会被缓存,因此甚至不考虑索引。

MySQL 每个语句只使用一个索引,因此覆盖索引(多列)是个好主意,但您必须对其进行测试才能确定。

【讨论】:

【参考方案3】:

您在 [Seller] 上的非集群索引可能有太多碎片,并且您的统计数据可能已过时,那么查询优化器可能不会选择最佳查询计划。检查碎片,更新统计信息,或者在卖家上重新构建你的非集群索引,当然如果你也可以为这个查询创建覆盖索引,如果这个查询被用户频繁使用,那么它是值得的。创建覆盖索引时,请确保最终用户最常使用的顺序。就像在您的查询中一样,覆盖索引应该在 [seller->col1->col3->col4]

【讨论】:

以上是关于为啥 MySQL 不使用索引?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 MySQL 中的这个查询不使用索引?

为啥 MySQL 不使用索引?

为啥 MySQL 不使用复合 WHERE IN 的索引?

为啥 MySQL 不使用 EXPLAIN 中的索引?

MySQL:为啥简单查询不使用索引,执行文件排序

为啥 MySQL 在这里并不总是使用索引合并?