IN子句中的项目数与索引使用的关系

时间:2017-06-02 17:34:57

标签: mysql optimization query-optimization amazon-rds

我正在尝试优化查询,但我看到了一种我不理解的奇怪行为。

我有一个包含近200万条记录的表,其中“status_code”列的索引是tinyint。

当我在In子句中用10个数字调用查询时,mysql会进行全表扫描

select * from `table` as t
where t.code in (1,2,3,4,5,6,7,8,9,10);

full scan

当我在IN子句中使用9个数字调用它时,将使用索引。

select * from `table` as t
where t.code in (1,2,3,4,5,6,7,8,9);

index 注意:此处的行数为“9”,尽管查询仅返回1行。

我正在使用Amazon RDS,我需要了解为什么会出现这种情况,以及是否有任何类型的配置可以控制它。

2 个答案:

答案 0 :(得分:1)

当您使用IN()谓词时,MySQL必须分析列表中每​​个值的索引,估计使用索引的好处。当您使用长值列表时,即使在执行查询之前,计算优化程序的估计也会变得很昂贵。

在MySQL 5.6中,他们建立了一个阈值,因此IN()谓词中的10个或更多项的列表跳过了每个值的索引潜值工作,并且只是猜测了使用索引的值。以前收集的有关指数的统计数据。这里记录了这一点:https://dev.mysql.com/doc/refman/5.6/en/range-optimization.html在“多值比较的等价范围优化”小节中。

您可以使用变量eq_range_index_dive_limit调整阈值。在MySQL 5.6中,默认值为10.在MySQL 5.7中,他们意识到默认值10太小,因此他们将默认值增加到200.您可以将此变量更改为200,就像MySQL 5.7行为一样。

我注意到您正在使用RDS。 RDS上的默认值有时与MySQL中的默认值不同,因此即使您使用的是基于MySQL 5.7的RDS,默认值也可能为10。查看db参数组。

答案 1 :(得分:0)

使用索引是由统计数据驱动的。我没有MySQL的精确信息,但如果计算结果大于表的2%,PostgreSQL将进行seq-scan。在你的情况下,它可以是其他值,但机制是相同的。

数据库使用统计信息来查看您的查询是否返回超过表的小百分比 - 在这种情况下 - 使用序列读取。如果表小于5MB,MS SQL Server将不使用索引 - 这更快。我的意思是 - 这是典型的,并且所有RDBMS都是这样的。有时失败 - 正如你所看到的那样。

怎么办?您可以analyze table更新统计信息。您可以使用提示use_stat_tables关闭存储的统计数据...在PostgreSQL中,您可以更改表格的直方图以获得更精确的结果,但我不知道MySQL的那些。还有很多驱动程序,这个特殊问题可以在这个级别解决。

提供explain s在这里不会有太大变化。 MySQL的解释很差,问题的性质也很明显。

作为旁注。这与RDS无关 - 这是RDBMS的典型问题。不同的系统以不同的方式处理它,MySQL不是这里的领导者。

相关问题