暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

count(*)

原创 胡佳伟 2020-03-13
1465

原文作者:Jonathan lewis
原文地址:https://jonathanlewis.wordpress.com/2020/02/25/count-again-2/

count(*) - again
-Jonathan Lewis 2020年2月25日下午1:24

我刚刚收到一封电子邮件,问了一个关于计算表中行数的问题。

我们有一个带有CLOB字段的大表,其中CLOB占用85%的存储空间。
当我们使用select count(*) from时,DBA说你不应该使用count(*),因为它会使用这个表的所有列包括CLOB字段,这会导致很高的CPU使用率,而如果使用count(rowid),会更快地查询出相同的结果。

我曾经不止一次地指出,count(*)、count(1)、count(声明为非空列)都将执行与count(*)相同的操作;我也列出了一些古怪的反常现象,也不止一次。然而,count(rowid)有一点不同,它没有被转化为count(*),我们可以从两个证据中看到:
例 A: 10053 (CBO) trace文件的一部分截取

----- Current SQL Statement for this session (sql_id=d381q70418ugs) ----- select count(rowid) from emp1  ... Final query after transformations:******* UNPARSED QUERY IS ******* SELECT COUNT("EMP1".ROWID) "COUNT(ROWID)" FROM "TEST_USER"."EMP1" "EMP1"

与转换为count(*)的各种count()调用不同,count rowids似乎不需要经过CNT(转换为count(*))转换,查询的最终状态仍然显示count(rowid)作为最终步骤。
例B: Column Projection Information的不同

SQL> explain plan for select count(1) from emp1; SQL> select * from table(dbms_xplan.display(null,null,'projection')); PLAN_TABLE_OUTPUT ---------------------------------------------------------------------------------- Plan hash value: 2110459082 ----------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ----------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 7 (15)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | INDEX FAST FULL SCAN| E1_PK | 20000 | 7 (15)| 00:00:01 | ----------------------------------------------------------------------- Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - (#keys=0) COUNT(*)[22] SQL> explain plan for select count(rowid) from emp1; SQL> select * from table(dbms_xplan.display(null,null,'projection')); PLAN_TABLE_OUTPUT ---------------------------------------------------------------------------------- Plan hash value: 2110459082 ------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 12 | 7 (15)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 12 | | | | 2 | INDEX FAST FULL SCAN| E1_PK | 20000 | 234K| 7 (15)| 00:00:01 | ------------------------------------------------------------------------------- Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - (#keys=0) COUNT(ROWID)[22] 2 - ROWID[ROWID,10]

count(1)查询转换为count(*),我们没有看到任何列信息在步骤2生成并传递给父操作。但是,在count(rowid)中,我们看到Oracle在步骤2中通过块地址和行目录构造实际的rowid,并将它们传递给父操作。

构造rowid并传递所消耗的CPU跟访问数据块相比是微不足道的。所以一开始我怀疑count(1)(或count(*))和count(rowid)之间是否有许多明显的时钟差异,但技术上看来count(rowid)会比任何经过count(*)转换的count要慢也更耗资源。

顺带,count(1)例子的执行计划也告诉我们,count(*)没有“使用所有列”-毕竟,不是大部分表,每一列都在主键里,emp1也不例外,执行计划是对主键索引进行快速全扫。

最后修改时间:2021-12-07 18:32:20
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论