我遇到过使用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亿.
执行摘要:这没有什么区别,而且在 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)
| 归档时间: |
|
| 查看次数: |
84 次 |
| 最近记录: |