前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Oracle和PG的count

Oracle和PG的count

作者头像
bisal
发布2019-05-08 10:32:36
8230
发布2019-05-08 10:32:36
举报

这是杂货铺的第463篇文章

曾经测试过Oracle 11g下count(*)、count(1)、count(主键列)和count(包含空值的列)这几种操作,究竟有何区别,结论如下,

11g下,通过实验结论,说明了count(1)和count(主键索引字段)其实都是执行的count(*),而且会选择索引的FFS扫描方式,count(包含空值的列)这种方式一方面会使用全表扫描,另一方面不会统计空值,因此有可能和业务上的需求就会有冲突,因此使用count统计总量的时候,要根据实际业务需求,来选择合适的方法,避免语义不同。

原文参考:《select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?》。

前几天,碰巧看见PostgreSQL中文社区发的一篇文章,关于在PG中count(1)和count(*)的效率问题,从结论看,和Oracle很像,但是他是从开源code,探究的整个过程,能够更准确地了解背后的原理,

写入count(1)与count(*)是相同的效果。 但是count(id)有些不同,它只计算id是NOT NULL的行数。 因此避免count(*)没有任何用处,反而count(*)的速度还会更快。

原文参考《PostgreSQL的count(1)真的比count(*)快么?》。

源码解读

  •     查看count函数定义
代码语言:javascript
复制

test=# select proname, pronargs, prosrc from pg_proc where proname='count';proname | pronargs | prosrc ---------+----------+-----------------count | 0 | aggregate_dummycount | 1 | aggregate_dummy(2 rows)

  • 什么? 0个参数的count?
代码语言:javascript
复制

test=# select count() from lzzhang;ERROR:  count(*) must be used to call a parameterless aggregate function

执行报错,说好的0个参数呢?

查看语法,仅保留主要代码。

代码语言:javascript
复制

* (*) - normal agg with no args * (aggr_arg,...) - normal agg with args * (ORDER BY aggr_arg,...) - ordered-set agg with no direct args

代码语言:javascript
复制
 * (aggr_arg,... ORDER BY aggr_arg,...) - ordered-set agg with direct args * * The zero-argument case is spelled with '*' for consistency with COUNT(*).aggr_args:  '(' '*' ')'                {                    $$ = list_make2(NIL, makeInteger(-1));                }

count(*)的*唯一的作用仅仅是作为count函数0个参数的标识使用!

  •      count查询

我们来看看几种count的情况,

代码语言:javascript
复制

test=# select * from lzzhang;id | id1 | id2 ----+-----+-----1 | | 1 | 1 | 1 | 1 | 12 | |

代码语言:javascript
复制

2 | | 3 | | 3 | | 3 | | (8 rows) test=# select count(*) from lzzhang;count -------8(1 row) test=# select count(1) from lzzhang;count -------8(1 row)

代码语言:javascript
复制

test=# select count('const_string') from lzzhang; count ------- 8(1 row) test=# select count(id) from lzzhang; count ------- 8(1 row) test=# select count(id1) from lzzhang; count ------- 2(1 row)

这里我们简单分成三种类型的count

1. 列名(id/id1)-只计算非null的数据

2. 无参(*)–计算全部数据

3. 常量(1/const_string)–计算全部数据

count只计算非null的数据。

三种方式在ExecInterpExpr函数中的处理

代码语言:javascript
复制

列名: EEO_CASE(EEOP_OUTER_FETCHSOME) { slot_getsomeattrs(outerslot, op->d.fetch.last_var); EEO_NEXT(); } 只计算非null的数据 常量: EEO_CASE(EEOP_CONST) { *op->resnull = op->d.constval.isnull;

代码语言:javascript
复制

*op->resvalue = op->d.constval.value; EEO_NEXT(); } 常量当然不会是null,所以1/const_string会计算全部数据。 无参: EEO_CASE(EEOP_AGG_STRICT_TRANS_CHECK) { AggState *aggstate; AggStatePerGroup pergroup; aggstate = op->d.agg_strict_trans_check.aggstate; pergroup = &aggstate->all_pergroups [op->d.agg_strict_trans_check.setoff] [op->d.agg_strict_trans_check.transno]; if (unlikely(pergroup->transValueIsNull))

代码语言:javascript
复制

EEO_JUMP(op->d.agg_strict_trans_check.jumpnull); EEO_NEXT(); } 检查之后就直接计算。

所以*并不会比1快,反而*比1会减少cpu的计算,速度更快!现在cpu的计算速度很快了,我的单核每秒可以计算6.5亿次,所以*和1的时间几乎是一样的。

可见,Oracle和PG对于一些操作,其实存在相同之处的,谈不上谁借鉴,可能更多地还是针对场景,为了满足业务以及性能方面的需求,提供的合理逻辑。其实我想说的是,无论是从10046,还是从PG的源码,我们应该看得深入一些,从原理设计层面,站在架构师、开发人员的视角,了解这个功能,设计的初衷,这才有助于我们借鉴好的设计,学以致用,丰富我们的经验,实现自我提高。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年04月22日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档