Group By 不使用索引
Group By not using index
有一个 table 有交易,它的行数是 2.2 亿,其中一列是 counterparty
。该列已编入索引。如果我 运行 像这样的普通查询:
select *
from <table>
where counterparty = 'X'
计划显示它使用索引。就好像我在同一列上使用 group by 一样,它不使用索引并进行 table 扫描。即:对于以下查询:
select counterparty, count(*)
from <table>
group by counterparty
能否请您指教,为什么它不使用 group by
的索引?仅供参考 - 我已经 运行 数据库统计信息。
仅供参考 - 第一次和第二次查询的计划如下所示:
注意 - 当我在具有相同索引的 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
被定义为可为空的列。因此,Oracle 不能仅依靠索引来生成 group by
查询的结果,因为结果中需要包含空值,但 (Oracle) 索引不包含空值。考虑到这一点,完整的 table 扫描是有意义的。
如果 counterparty
没有充分的理由可以为 null,请继续并使其成为 not null
。然后执行计划应更改为按预期使用索引。
或者,如果您不能进行该更改,但您不关心此特定查询的空值,则可以调整查询以显式过滤我们的空值。这也应该会产生更好的执行计划。
select counterparty, count(*)
from tbl
where counterparty is not null -- add this filter
group by counterparty
注意:我不是 Sybase 专家,但我假设索引包含空值。 Oracle 索引不包括空值。这将解释两个数据库之间执行计划的差异。
有一个 table 有交易,它的行数是 2.2 亿,其中一列是 counterparty
。该列已编入索引。如果我 运行 像这样的普通查询:
select *
from <table>
where counterparty = 'X'
计划显示它使用索引。就好像我在同一列上使用 group by 一样,它不使用索引并进行 table 扫描。即:对于以下查询:
select counterparty, count(*)
from <table>
group by counterparty
能否请您指教,为什么它不使用 group by
的索引?仅供参考 - 我已经 运行 数据库统计信息。
仅供参考 - 第一次和第二次查询的计划如下所示:
注意 - 当我在具有相同索引的 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
被定义为可为空的列。因此,Oracle 不能仅依靠索引来生成 group by
查询的结果,因为结果中需要包含空值,但 (Oracle) 索引不包含空值。考虑到这一点,完整的 table 扫描是有意义的。
如果 counterparty
没有充分的理由可以为 null,请继续并使其成为 not null
。然后执行计划应更改为按预期使用索引。
或者,如果您不能进行该更改,但您不关心此特定查询的空值,则可以调整查询以显式过滤我们的空值。这也应该会产生更好的执行计划。
select counterparty, count(*)
from tbl
where counterparty is not null -- add this filter
group by counterparty
注意:我不是 Sybase 专家,但我假设索引包含空值。 Oracle 索引不包括空值。这将解释两个数据库之间执行计划的差异。