MySQL 8.0.28中覆盖索引(含函数索引)未被使用的问题排查
问题原因分析
你的查询未触发Using index的核心原因是:MySQL优化器未将查询中case语句里的length(cleaned_text)与索引中预计算的表达式值关联起来,默认会尝试从原表的cleaned_text字段重新计算长度,导致需要回表访问底层数据。
虽然你创建的索引ix_site_header_to_cleaned_text2包含了sp_site_foreign_key和length(cleaned_text)的预计算结果,但在你的查询逻辑中,length(cleaned_text)是作为新的函数调用出现的,优化器没有自动识别到这个计算结果已经存在于索引中,因此会判定需要读取原表的cleaned_text字段来完成计算,这就打破了覆盖索引(无需回表)的使用条件。
解决方法
要让优化器使用覆盖索引,你需要明确引导它直接使用索引中的预计算值,最直接的方式是通过子查询先提取索引包含的字段和表达式结果,再在外部进行分组统计:
EXPLAIN SELECT sp_site_foreign_key, count(case when len_cleaned > 100 then 1 else NULL END) as num1, count(1) as num2 FROM ( SELECT sp_site_foreign_key, length(`cleaned_text`) as len_cleaned FROM sp_files USE INDEX (`ix_site_header_to_cleaned_text2`) ) t GROUP by sp_site_foreign_key;
此时子查询的EXPLAIN结果会显示Using index,因为它仅从索引中获取所需数据,无需回表;外层查询则基于子查询的结果完成分组统计。
另外,你也可以尝试将查询中的length(cleaned_text)与索引定义的表达式完全对齐(确保函数调用、字段名完全一致),部分场景下优化器会识别到可以复用索引中的预计算值,但子查询的方式更稳定可靠。
内容的提问来源于stack exchange,提问作者Zoltan Fedor
相关产品推荐
相关产品推荐

