为啥mysql解释说'使用索引'而使用的索引不包含必填字段

Posted

技术标签:

【中文标题】为啥mysql解释说\'使用索引\'而使用的索引不包含必填字段【英文标题】:why mysql explain says 'using index' while the index used do not contain required fields为什么mysql解释说'使用索引'而使用的索引不包含必填字段 【发布时间】:2016-06-08 03:30:08 【问题描述】:

这是 mysql(innodb) 中解释命令的输出:

explain select * from multi_index_test_tbl_1 force index(`query_index_1`) where `text_field1`='0' order by `numeric_field2` desc limit 1000000;
+----+-------------+------------------------+------+---------------+---------------+---------+-------+----------+--------------------------+
| id | select_type | table                  | type | possible_keys | key           | key_len | ref   | rows     | Extra                    |
+----+-------------+------------------------+------+---------------+---------------+---------+-------+----------+--------------------------+
|  1 | SIMPLE      | multi_index_test_tbl_1 | ref  | query_index_1 | query_index_1 | 386     | const | 53547628 | Using where; Using index |
+----+-------------+------------------------+------+---------------+---------------+---------+-------+----------+--------------------------+

multi_index_test_tbl_1的架构如下:

CREATE TABLE IF NOT EXISTS `multi_index_test_tbl_1` 
(
    `text_field1` varchar(128) NOT NULL,
    `numeric_field1` float NOT NULL,
    `numeric_field2` float NOT NULL,
    `text_field2` varchar(128) NOT NULL,
    PRIMARY KEY (`text_field1`,`numeric_field1`,`text_field2`),
    KEY `query_index_1` (`text_field1`,`numeric_field2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

似乎使用了query_index_1。并且“使用索引”出现在Extra 中,而索引query_index_1 不包含表multi_index_test_tbl_1 中的所有字段。

因为 mysql 文档是这样说的:

使用索引(JSON 属性:using_index)

仅使用索引树中的信息从表中检索列信息,而无需进行额外的查找以读取实际行。当查询仅使用属于单个索引的列时,可以使用此策略。

我很困惑这里到底发生了什么。

【问题讨论】:

@zerkms mysql 文档说using index 表示使用only information in the index 检索列 为什么不显示表架构?你为什么要强制索引然后想知道为什么它说“好的,我会使用那个索引” @Drew 抱歉,我已经添加了架构。但问题是:根据官方文档,using index 不仅表示使用了索引,还表示没有使用实际行(因此是聚集索引)。 您意识到explain 返回的信息中有一半有时是边缘幻想之地。您要求例行程序在一瞬间将信息返回给我们不耐烦的消费者。并在那一瞬间确定其所谓的计划。它可以在实际运行时愉快地偏离。并且该执行可能需要长达 10 个小时才能运行(当不使用 explain 但实际运行时)。 【参考方案1】:

啊,但它确实“包含必填字段”。详细说明...

InnoDB 在每个“二级”索引中包含PRIMARY KEY 的所有列。所以,

KEY `query_index_1` (`text_field1`,`numeric_field2`)

真的更像

KEY `query_index_1` (`text_field1`,`numeric_field2`,
                     `numeric_field1`,`text_field2`)

在您的示例中,这包括所有列。因此,SELECT 中的所有内容,包括*,都可以在该二级索引中找到。所以,“使用索引”是“正确的”。

这是 InnoDB 有时优于 MyISAM 的一种方式。

请尝试EXPLAIN FORMAT=JSON SELECT ... 了解更多详情。

【讨论】:

这就是答案!我已经通过一些测试表的实验证实了这一点。

以上是关于为啥mysql解释说'使用索引'而使用的索引不包含必填字段的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 专家:为啥 2 个查询给出不同的“解释”索引使用结果?

为啥 MySQL 不使用索引?

为啥MongoDB采用B树索引,而Mysql用B+树做索引

Mysql 不使用包含两列的索引

mysql 为啥总是推荐使用联合索引而不是单值索引

为啥在另一个数据库中执行相同查询时不使用索引?