(CSDN博主:写代码也要符合基本法)
长久以来,关于 Oracle 中 COUNT 函数的使用可谓众说纷纭,江湖门派林立,直叫人摸不着头(tou)脑(fa)。
SQL> SELECT COUNT(NULL) FROM cux_count_test;
COUNT(NULL)
-----------
0
复制
十万行数据直接给你整没
SQL> SELECT COUNT(*) FROM (SELECT NULL, NULL FROM dual);
COUNT(*)
----------
1
复制
由此我们可知,COUNT(*) 和 COUNT(COL) 的区别:同上。
SQL> SELECT COUNT(*) FROM cux_count_test;
----------------------------------------------------------
| Id | Operation | Name | Cost (%CPU)|
----------------------------------------------------------
| 0 | SELECT STATEMENT | | 759 (100)|
| 1 | SORT AGGREGATE | | |
| 2 | TABLE ACCESS FULL| CUX_COUNT_TEST | 759 (1)|
----------------------------------------------------------
复制
执行计划中甚至没有 BYTES 信息。
DECLARE
l_begin_time NUMBER;
l_end_time NUMBER;
l_count NUMBER;
BEGIN
FOR j IN 1 .. 50 LOOP
l_begin_time := dbms_utility.get_time;
FOR k IN 1 .. 100 LOOP
EXECUTE IMMEDIATE 'select count(col' || j || ') from cux_count_test'
INTO l_count;
END LOOP;
l_end_time := dbms_utility.get_time;
dbms_output.put_line((l_end_time - l_begin_time) 100);
END LOOP;
END;
复制
将运行结果复制到 Excel,使用生涩的手法制作一张折线图:
可见,列在表中的位置越靠后,对其做聚合统计所需时间就越多。
SQL> SELECT COUNT(col1) FROM cux_count_test;
----------------------------------------------------------
| Id | Operation | Name | Cost (%CPU)|
----------------------------------------------------------
| 0 | SELECT STATEMENT | | 759 (100)|
| 1 | SORT AGGREGATE | | |
| 2 | TABLE ACCESS FULL| CUX_COUNT_TEST | 759 (1)|
----------------------------------------------------------
SQL> SELECT COUNT(col50) FROM cux_count_test;
----------------------------------------------------------
| Id | Operation | Name | Cost (%CPU)|
----------------------------------------------------------
| 0 | SELECT STATEMENT | | 759 (100)|
| 1 | SORT AGGREGATE | | |
| 2 | TABLE ACCESS FULL| CUX_COUNT_TEST | 759 (1)|
----------------------------------------------------------
复制
原理至少有两个,单列的B树索引不会存储列中的空值,如此在只计算索引列的行数时,访问索引结构完全无需回表。
例如我们在实验表第一列增加索引后再观察执行计划的变化:
SQL> SELECT COUNT(col1) FROM cux_count_test;
-----------------------------------------------------------
| Id | Operation | Name | Cost (%CPU)|
-----------------------------------------------------------
| 0 | SELECT STATEMENT | | 224 (100)|
| 1 | SORT AGGREGATE | | |
| 2 | INDEX FULL SCAN| CUX_COUNT_TEST_N1 | 224 (2)|
-----------------------------------------------------------
复制
不仅完全忽略了字节信息,而且执行成本大大降低,这是因为语句仅访问了体积更小的索引块,而不需再访问表数据块。
最后,回归到 COUNT 执行的工作本质上,无非就是数数,此刻我们关注编码需求本身,如果可以让 COUNT 去数更少行数的结果集就能满足我们的需要,岂不美哉?
比如,我们只想知道表中是否存在符合某些条件的记录,不会真的有人会实在到把这些记录每一行都去数一遍吧,不会吧,不会吧?
SQL> SELECT COUNT(1) FROM cux_count_test WHERE col2 = 1;
------------------------------------------------------------------
| Id | Operation | Name | Bytes | Cost (%CPU)|
------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | 760 (100)|
| 1 | SORT AGGREGATE | | 13 | |
|* 2 | TABLE ACCESS FULL| CUX_COUNT_TEST | 1144 | 760 (1)|
------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("COL2"=1)
SQL> SELECT COUNT(1)
2 FROM cux_count_test
3 WHERE col2 = 1
4 AND rownum = 1;
-------------------------------------------------------------------
| Id | Operation | Name | Bytes | Cost (%CPU)|
-------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | 760 (100)|
| 1 | SORT AGGREGATE | | 13 | |
|* 2 | COUNT STOPKEY | | | |
|* 3 | TABLE ACCESS FULL| CUX_COUNT_TEST | 1144 | 760 (1)|
-------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(ROWNUM=1)
3 - filter("COL2"=1)
复制


文章转载自SQL干货分享,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。