分组方式不使用索引

Posted

技术标签:

【中文标题】分组方式不使用索引【英文标题】:Group By not using index 【发布时间】:2016-07-30 03:21:25 【问题描述】:

有一个表有交易,它的行数是2.2亿,其中一列是counterparty。该列已编入索引。如果我运行正常查询,例如:

select * 
  from <table> 
 where counterparty = 'X'

计划显示它使用索引。就好像我在同一列上使用 group by 一样,它不使用索引并进行表扫描。即:对于以下查询:

select counterparty, count(*)
  from <table>
 group by counterparty

您能否告知,为什么它不使用group by 的索引?仅供参考 - 我已经运行了 db stats。

仅供参考 - 第一次和第二次查询的计划如下所示:

注意 - 当我在 Sybase 中使用相同的 group by 和相同的索引时,我们正在将数据从 Sybase 迁移到 oracle。该查询使用索引,但不在 oracle 中。

首先

Plan hash value: 350128866

| Id  | Operation                   | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
|   0 | SELECT STATEMENT            |                     |  2209 |  1469K|   914   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| FXCASHTRADE         |  2209 |  1469K|   914   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | SCB_FXCASHTRADE_002 |  2209 |       |    11   (0)| 00:00:01 |


Predicate Information (identified by operation id):

    2 - access("COUNTERPARTY"='test')

第二

> Plan hash value: 2920872612

| Id  | Operation          | Name        | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
|   0 | SELECT STATEMENT   |             |   100K|  2151K|       |  6558K  (1)| 00:00:38 |
|   1 |  HASH GROUP BY     |             |   100K|  2151K|  6780M|  6558K  (1)| 00:00:38 |
|   2 |   TABLE ACCESS FULL| FXCASHTRADE |   221M|  4643M|       |  6034K  (1)| 00:00:35 |

【问题讨论】:

counterparty 是可以为空的列吗? 感谢您的回复,是的,它是可为空的列。但是拇指规则组不会用于所有可为空的列吗?或者它取决于优化器。 【参考方案1】:

我将做出有根据的猜测,并说counterparty 被定义为可为空的列。因此,Oracle 不能仅仅依靠索引来生成group by 查询的结果,因为空值需要包含在结果中,但是(Oracle)索引不包括空值。考虑到这一点,全表扫描是有意义的。

如果没有充分的理由让counterparty 可以为空,请继续将其设为not null。然后执行计划应更改为按预期使用索引。

或者,如果您无法进行更改,但您不关心此特定查询的空值,您可以调整查询以显式过滤我们的空值。这也应该会产生更好的执行计划。

select counterparty, count(*)
  from tbl
 where counterparty is not null -- add this filter
 group by counterparty

注意:我不是 Sybase 专家,但我假设索引包含空值。 Oracle 索引不包含空值。这可以解释两个数据库之间执行计划的差异。

【讨论】:

非常感谢,这确实有帮助。在我添加 not null 后,它开始使用 index.html。抱歉,但我还有一个问题:这是拇指规则,如果一列有 null,那么该列上的 group by 将不使用索引?我在另一个没有“非空”约束的列上使用了相同的查询,但是该列上的 group by 使用了索引(虽然不同)。所以我有点困惑,优化器是如何工作的。 没有看到查询就不能说。我的猜测是查询必须有一些过滤子句隐含地使空值无法返回。如果是这种情况,Oracle 将能够利用该索引。但是,是的,我会说经验法则是,如果您有一个按索引列分组的查询,其中查询的结果可能为该列返回空值,那么不要指望优化器使用索引.

以上是关于分组方式不使用索引的主要内容,如果未能解决你的问题,请参考以下文章

MySQL:与案例一起使用时按子句分组不使用索引

Ext JS 4.2分组中的行索引不正确

Pcb的组织方式优缺点

索引使用建议及索引的优缺点

Mysql原理篇之索引不懂不要瞎用---04

创建单词列表并按索引分组