首页 > 解决方案 > 返回某些列时不使用 MySQL 索引

问题描述

我有一个表,其中包含一个created_on自身索引的字段。当查看一个慢查询时,我意识到根据我返回的列不使用索引。在以下两个示例中,我有foobar列。


EXPLAIN SELECT created_on, foo FROM T1
WHERE created_on > NOW() - INTERVAL 5 DAY;

未使用索引,搜索了 +3 百万行。( Using where)

如果我添加一个LIMIT子句,它将使用索引。

EXPLAIN SELECT created_on, foo FROM T1
WHERE created_on > NOW() - INTERVAL 5 DAY
LIMIT 1000;

如果使用另一列bar,它也将使用索引。

EXPLAIN SELECT created_on, bar FROM T1
WHERE created_on > NOW() - INTERVAL 5 DAY;

使用了索引,只搜索了 150 万行。( Using where; Using index)

为什么 MySQL 会跳过这些查询之一的索引?

标签: mysqlsqlindexingmariadb

解决方案


SELECT created_on, foo FROM T1
WHERE created_on > NOW() - INTERVAL 5 DAY;

优化器可能会也可能不会使用INDEX(created_on). 这取决于过去 5 天内创建的行占表的百分比。将使用一小部分(例如,低于 20%)的索引。

另一方面,INDEX(created_on, foo)(按此顺序)因为它将“覆盖”。

foo 是具有其他三列的另一个索引的一部分。

索引中列的顺序非常重要。SHOW CREATE TABLE如果您需要进一步讨论,请提供。

如果使用另一个列栏,它也将使用索引。

该指数可能PRIMARY KEY. SHOW CREATE TABLE如果您需要进一步讨论,请提供。

(使用 where;使用索引)

“使用索引”意味着所有必要的列都在索引中。因此,只需要查看索引的 BTree。每个二级索引都隐含地包含其中的PRIMARY KEY列。所以,我推断你有INDEX(bar) 并且 created_atPRIMARY KEY.

为什么 MySQL 会跳过这些查询之一的索引?

优化器会询问哪个更快(通常会给出正确答案):

  • 索引是“覆盖”的,所以我们只使用索引。
  • 让我们使用索引,但在它与数据的 BTree 之间跳转以获取其他一些列。
  • 我不能用 ; 做很多事情WHERE,但我可以使用 ; 的索引ORDER BY。让我们这样做,并希望我不必扫描太多行。
  • 平底船。WHERE让我们忽略所有索引并简单地扫描数据,丢弃任何与子句不匹配的行。

是的,最后一个选项通常是最快的。一些可能的特征:

  • 没有二级索引对WHERE.
  • 有一个WHERE,但它不会消除很多行。
  • ORDER BY,或没有索引匹配它。
  • 没有LIMIT

如果使用 MySQL,EXPLAIN FORMAT=JSON SELECT ...将提供它为做出决定所做的“基于成本”的计算。

我的食谱有助于建立最佳索引。


推荐阅读