为啥 mysql 优化器没有使用完整的索引?
Posted
技术标签:
【中文标题】为啥 mysql 优化器没有使用完整的索引?【英文标题】:Why the mysql optimizer is not using the complete index?为什么 mysql 优化器没有使用完整的索引? 【发布时间】:2015-03-27 13:14:12 【问题描述】:我试图理解为什么 mysql 不使用完整索引来回答查询。让我解释。 我通过 MySQL 版本 5.1.73-1 (Debian) 使用 imdb 数据库。我在movie_info_idx 表上创建并索引“itid_inf25_mid_ndx”,其中包含列(info_type_id、info(25)、movie_id)。 info_type_id 和movie_id 列是整数(NOT NULL),info 是TEXT 类型,因此每个索引条目占用4+27+4 = 35 个字节。句子的输出:
EXPLAIN
SELECT movie_id
FROM movie_info_idx
WHERE info_type_id = 101
AND info > "9";
显示这些值:
select_type = 简单;表=电影信息IDX;类型=范围; 可能键= itid_inf25_mid_ndx;键= itid_inf25_mid_ndx; key_len = 31;参考=空;行 = 841; Extra = "使用位置"
key_len 列和extra 列中没有“使用索引”表明只有总和4+27 = 31 个字节的列(info_type_id,info(25)) 正在使用索引。我想知道为什么优化器不使用索引中的movie_id 列来访问SELECT 子句中的movie_id?似乎优化器将访问基表movie_info_idx 以获取我要列出的movie_id 值。为什么?
提前感谢您的回复。
【问题讨论】:
【参考方案1】:一旦 MySQL 使用查询进行“范围扫描”(匹配多个值),它通常将不再使用最后一列。
原因是多列索引是一棵树。为了扫描最后一列 (movie_id) 上的索引,它必须在索引树中搜索范围列 (info) 的每个匹配值。这通常效率低下,因此 MySQL 不会这样做。
为了改善这种情况,将预期作为范围扫描的列放在最后,因此将其排序为 (info_type_id, movie_id, info)
更多信息: https://dev.mysql.com/doc/refman/5.6/en/multiple-column-indexes.html
【讨论】:
谢谢Trent,但是查询不使用第三列来过滤行。 Mysql 将使用索引来检索 info_type_id = 101 的条目,这定义了一个索引切片。然后可以通过获取具有 info > "9" 值的条目来缩小切片,并且可以这样做,因为 info 是索引中的第二列(如果将 info 作为第三列,mysql 将无法使用它为了缩短切片)。在检索到最后一个切片 (101, > "9", *) 之后,所有必要的 movie_id 都在这些索引切片中,但是处理器转到表中以便检索它们为什么?。 啊,是的,对不起,但答案基本相同。一旦完成范围扫描,MySQL 通常不会使用索引中的下一列。这样做实际上可能同样有效(实际上不确定),但 MySQL 通常不会这样做。 啊好吧,这是一个令人信服的答案。感谢您的关注。以上是关于为啥 mysql 优化器没有使用完整的索引?的主要内容,如果未能解决你的问题,请参考以下文章
技术分享 为啥 SELECT 查询选择全表扫描,而不走索引?
SpringBoot入门教程:MySQL8新特性(优化器索引)
SpringBoot入门教程:MySQL8新特性(优化器索引)