始终是真正的条件聚合与计数

Twe*_*fth 5 sql oracle

我遇到过使用1 = 1条件聚合而不是计数的编码

select sum(case when 1=1 then 1 else 0 end)
Run Code Online (Sandbox Code Playgroud)

在我看来,这相当于:

select count(1)
Run Code Online (Sandbox Code Playgroud)

起初我认为这是一个占位符,开发人员打算在这个条件聚合中重新访问一些额外的逻辑,但后来我在另一个脚本中找到它,然后是另一个脚本.这促使我四处询问,我发现之前的开发人员已经强调,这个总和条件在所有情况下都比计数函数更有效和更快(强调它足以让其他开发人员遵循以后的标准).对我来说似乎非常直观,迫使系统评估1 = 1条件可能很小,但它仍然是计数函数的额外工作.在我回来之前,我会在这里进行咨询.

a)这个开发人员说有条件聚合比计数更快是否有任何道理

完全是一个问题:b)有没有一个数据库系统可以比计数更快地评估条件聚合?

这是一个oracle 11g数据库,但我怀疑脚本是为oracle 8i编写的

作为奖励积分...我被要求优化此代码.将删除替换为计数函数会改善速度吗?记录数有时超过1亿.

Wil*_*son 3

执行摘要:这没有什么区别,而且在 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');
Run Code Online (Sandbox Code Playgroud)

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

巧妙的超快表达:

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

请注意谓词部分,其中显示表达式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)
Run Code Online (Sandbox Code Playgroud)

这是没有过滤器的计划:

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

正如你所看到的,它们都是一样的(除了我的人工过滤条件的差异)。

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