技术分享 为啥 SELECT 查询选择全表扫描,而不走索引?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了技术分享 为啥 SELECT 查询选择全表扫描,而不走索引?相关的知识,希望对你有一定的参考价值。

参考技术A SQL的执行成本(cost)是 mysql 优化器选择 SQL 执行计划时一个重要考量因素。当优化器认为使用索引的成本高于全表扫描的时候,优化器将会选择全表扫描,而不是使用索引。

下面通过一个实验来说明。

如下结构的一张表,表中约有104w行数据:

查询1,并未用到ct_index(create_time)索引:

而查询2,则用到了ct_index(create_time)索引:

这里使用optimizer trace工具,观察MySQL对SQL的优化处理过程:

获得关于此SQL的详细优化器处理信息:

通过逐行阅读,发现优化器在join_optimization(SQL优化阶段)部分的rows_estimation内容里:

通过观察优化器的信息,不难发现,使用索引扫描行数约52w行,而全表扫描约为104w行。为什么优化器反而认为使用索引的成本比全表扫描还高呢?

因为当ct_index(create_time)这个普通索引并不包括查询的所有列,因此需要通过ct_index的索引树找到对应的主键id,然后再到id的索引树进行数据查询,即回表(通过索引查出主键,再去查数据行),这样成本必然上升。尤其是当回表的数据量比较大的时候,经常会出现MySQL优化器认为回表查询代价过高而不选择索引的情况。

这里可以回头看查询1 和 查询2的数据量占比:

另外,在MySQL的官方文档中对此也有简要的描述:

https://dev.mysql.com/doc/refman/5.7/en/where-optimization.html

参考文档:

https://opensource.actionsky.com/20201127-mysql/

https://blog.csdn.net/CSDNcircular/article/details/107253747

为啥我的查询仍然在 Redshift 中使用 sortkey 进行全表扫描?

【中文标题】为啥我的查询仍然在 Redshift 中使用 sortkey 进行全表扫描?【英文标题】:Why does my query still do a full table scan with sortkey in Redshift?为什么我的查询仍然在 Redshift 中使用 sortkey 进行全表扫描? 【发布时间】:2018-03-23 21:55:08 【问题描述】:

假设我们有一个表 table1,字段 1 为 INT ENCODE ZSTD,我们在字段 1 上添加了交错排序键。

但是当我查询select * from table1 where field1=123; 时,我仍然看到对整个表的顺序扫描,我认为这应该是对表的子扫描。

我对排序键有什么误解吗?

【问题讨论】:

【参考方案1】:

1) 根据您的说法,您不需要交错排序键,因为您只有一列感兴趣。当您希望多列同样重要时,您需要交错排序键,因为您想要运行where col1=123where col2=123 类型的查询。这为大型表提供了好处。

2) 压缩排序键列被认为是一种不好的做法。 Proof from Amazon:the first column in a compound sort key should not be encoded(一栏键相同)。整篇文章其实很有用,看完不后悔

3) 配置排序键并填充数据后,最好运行 Vacuum 并分析命令,以确保根据排序键对行进行排序并更新表统计信息。

【讨论】:

那里有更多的字段。只是有点懒得把它们都放在这里。 (我们有超过 100 列) 我认为我不需要复合排序键,因为执行查询的模式并不总是相同。并且之前也运行过真空和分析。 亚历克斯很聪明。听亚历克斯。 :) 或者阅读我们的“高级表格设计手册”以获得更详细的解释。 aws.amazon.com/blogs/big-data/…

以上是关于技术分享 为啥 SELECT 查询选择全表扫描,而不走索引?的主要内容,如果未能解决你的问题,请参考以下文章

mysql select * order by 索引 limit0,10 为啥是全表扫描

为啥 oracle 表索引但仍然进行全表扫描?

mysql 证明为啥用limit时,offset很大会影响性能

MySQL视图是不是总是进行全表扫描?

为啥 Oracle 在应该使用索引时使用全表扫描?

优化 SQL 查询以避免全表扫描