按不使用索引分组

Man*_*h V 2 sql oracle database-indexes

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

select * 
  from <table> 
 where counterparty = 'X'
Run Code Online (Sandbox Code Playgroud)

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

select counterparty, count(*)
  from <table>
 group by counterparty
Run Code Online (Sandbox Code Playgroud)

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

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

注意 - 当我group by在具有相同索引的 Sybase 中使用相同的数据时,我们正在将数据从 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')
Run Code Online (Sandbox Code Playgroud)

第二

> 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 |
Run Code Online (Sandbox Code Playgroud)

sst*_*tan 5

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

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

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

select counterparty, count(*)
  from tbl
 where counterparty is not null -- add this filter
 group by counterparty
Run Code Online (Sandbox Code Playgroud)

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