select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?

下班路上看见网上有人问一个问题:

oracle 10g以后count(*)和count(非空列)性能方面有什么区别?

乍一看,确实有些含糊,Oracle中往往小问题蕴含着大智慧,如何破云见日?

最直接的方法,我想就是通过10053事件,来看下不同SQL对应的执行计划和资源消耗等情况,进而看看是否有些信息可以为我们所用。

首先,准备测试数据,11g库表bisal的id1列是主键(确保id1列为非空),id2列包含空值,
select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?

我们分别用10053打印如下4组SQL的trace,


SQL1:select count(*) from bisal;
SQL2:select count(1) from bisal;
SQL3:select count(id1) from bisal;
SQL4:select count(id2) from bisal;

我们来看下这四个SQL的执行结果,
select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?

前三个均为表数据总量,第四个SQL结果是99999,仅包含非空记录数据量,说明若使用count(允许空值的列),则统计的是非空记录的总数,空值记录不会统计,这可能和业务上的用意不同。

我们在看下这四个SQL对应的执行计划,前三个SQL执行计划相同,均为对主键索引的快速索引全扫描,
select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?

第四个SQL执行计划,则是全表扫描,
select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?

其实这无论id2是否包含空值,使用count(id2)均会使用全表扫描,因此即使语义上使用count(id2)和前三个SQL一致,这种执行计划的效率也是最低的,这张测试表的字段设置和数据量不很夸张,因此不很明显,如果数据表字段多、数据量大,显然主键索引占用的数据块要比数据表占用的数据块少,因此仅索引扫描,而且是全索引快速扫描(多块读),消耗的资源会更少些了。

再看前三个SQL对应的trace,第1个SQL,
select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?

select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?

第二个SQL,
select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?

select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?

第三个SQL,
select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?

select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?

可以看出一个问题,就是这三个SQL经过Oracle转换,执行的SQL其实都是select count(*) from bisal,因此对应的执行计划成本选择,这三个SQL相同,
select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?
比较了全表扫描、索引快速全扫描以及全索引扫描这三种扫描方式的成本,都选择了主键索引的FFS扫描方式。

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

如果您觉得此篇文章对您有帮助,欢迎关注微信公众号:bisal的个人杂货铺,您的支持是对我最大的鼓励!共同学习,共同进步:) select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> select count(*)、count(1)、count(主键列)和count(包含空值的列)有何区别?


 上一篇
一个执行计划异常变更的案例 – 外传之SQL Profile(下) 一个执行计划异常变更的案例 – 外传之SQL Profile(下)
之前的几篇文章:《一个执行计划异常变更的案例 - 前传》《一个执行计划异常变更的案例 - 外传之绑定变量窥探》《一个执行计划异常变更的案例 - 外传之查看绑定变量值的几种方法》《一个执行计划异常变更的案例 - 外传之rolling inva
下一篇 
一个执行计划异常变更的案例 – 正传 一个执行计划异常变更的案例 – 正传
前天推送过这篇文章,但忘了加参考文章链接了,这篇是有文章链接的版本,方便查阅历史文章。 之前的几篇文章:  从这个系列第一篇开始,一共写了12篇小文,其中涉及的知识点都是这案例实际使用的,一路写来,也让自己对这些知识做了一次梳理,有了新认识