mysql - 返回某些列时不使用 MySQL 索引
问题描述
我有一个表,其中包含一个created_on
自身索引的字段。当查看一个慢查询时,我意识到根据我返回的列不使用索引。在以下两个示例中,我有foo
和bar
列。
foo
是具有其他三列的另一个索引的一部分。bar
根本没有索引。
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 会跳过这些查询之一的索引?
解决方案
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_at
在PRIMARY KEY
.
为什么 MySQL 会跳过这些查询之一的索引?
优化器会询问哪个更快(通常会给出正确答案):
- 索引是“覆盖”的,所以我们只使用索引。
- 让我们使用索引,但在它与数据的 BTree 之间跳转以获取其他一些列。
- 我不能用 ; 做很多事情
WHERE
,但我可以使用 ; 的索引ORDER BY
。让我们这样做,并希望我不必扫描太多行。 - 平底船。
WHERE
让我们忽略所有索引并简单地扫描数据,丢弃任何与子句不匹配的行。
是的,最后一个选项通常是最快的。一些可能的特征:
- 没有二级索引对
WHERE
. - 有一个
WHERE
,但它不会消除很多行。 - 否
ORDER BY
,或没有索引匹配它。 - 没有
LIMIT
。
如果使用 MySQL,EXPLAIN FORMAT=JSON SELECT ...
将提供它为做出决定所做的“基于成本”的计算。
我的食谱有助于建立最佳索引。
推荐阅读
- java - “java.lang.StringIndexOutOfBoundsException:字符串索引超出范围:68”是什么意思?
- css - 100vh 弹性项目不是全高
- angular - Angular - 解析多个文件不起作用
- java - FileChooser - 如何在将 json 文件保存为 png 或任何其他格式时显示错误消息
- ios - 如何在 Apple 证书过期之前生成警报?
- excel - 如何使用VBA计算时间差?
- android - Flutter:异步任务在“initState()”中无法按预期工作
- react-native - null 不是对象。RNGestureHandlerModule-Direction
- php - get_user_meta 在functions.php 文件中不起作用
- go - 如何分割/拆分文件中的单词