执行摘要:它没有任何区别,而且在 Oracle 中从来没有,至少从版本 6 (1989) 开始,我第一次开始听说通过选择主键列等来加快计数的聪明方法,就好像 Oracle 是不知道人们有时会计算事物。
您可以通过在过滤器中使用表达式并检查执行计划的“谓词”部分来查看解析器/优化器对表达式的作用。
create table demo
( demo_id integer generated always as identity constraint demo_pk primary key
, othercolumn integer );
insert into demo (othercolumn) select dbms_random.value(0,1000)
from dual connect by rownum <= 10000;
commit;
call dbms_stats.gather_table_stats(user, 'demo');
普通count(*)(Oracle 12.1):
select count(*) from demo
having count(*) > 1
Plan hash value: 1044424301
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 (0)| 00:00:01 |
|* 1 | FILTER | | | | |
| 2 | SORT AGGREGATE | | 1 | | |
| 3 | INDEX FAST FULL SCAN| DEMO_PK | 10000 | 7 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(COUNT(*)>1)
聪明的超快表达:
select sum(case when 1=1 then 1 else 0 end) from demo
having sum(case when 1=1 then 1 else 0 end) > 0
Plan hash value: 1044424301
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 (0)| 00:00:01 |
|* 1 | FILTER | | | | |
| 2 | SORT AGGREGATE | | 1 | | |
| 3 | INDEX FAST FULL SCAN| DEMO_PK | 10000 | 7 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(SUM(1)>0)
请注意谓词部分,该部分显示sum 表达式已被计算并替换为sum(1)。 (我现在没有时间深入研究跟踪文件,但我很确定它们会表明重写发生在 CBO 优化之前。)
下面是它对count(1) 的作用,这是另一种有时被认为比标准表达式更有效的表达式:
select count(1) from demo
having count(1) > 1
Plan hash value: 1044424301
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 (0)| 00:00:01 |
|* 1 | FILTER | | | | |
| 2 | SORT AGGREGATE | | 1 | | |
| 3 | INDEX FAST FULL SCAN| DEMO_PK | 10000 | 7 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(COUNT(*)>1)
这是没有过滤器的计划:
select sum(case when 1=1 then 1 else 0 end) as rowcount
from demo
Plan hash value: 2242940774
-------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| DEMO_PK | 10000 | 7 (0)| 00:00:01 |
-------------------------------------------------------------------------
如您所见,它们都是相同的(除了我的人工过滤条件不同)。
另外,当没有行时,sum(1) 不会给出与count(*) 相同的结果:
select sum(case when 1=1 then 1 else 0 end) as sum1
, count(*)
from demo
where 1=2
SUM1 COUNT(*)
---------- ----------
0