一、问题:
有一次,我和同事聊起了OUNT(字段)和COUNT(1)与COUNT(*)哪一个比较快,执行效率问题,我们感觉总觉得 * 这个符号会将Oracle中所有的字段记录会返回,而COUNT(1)只是统计了1的个数,相对比下就自认为COUNT(1)要快一些。然后真的是这样吗?
二、Oracle存储机制
Oracle是关系型数据库。与Hbase等非关系型数据库不同的,Oracle的存储形式是采用行式存储的。行式存储也就是将表中的数据一行行的写入数据块。而数据块是Oracle的最小单位。每次我们在查询数据的时候,Oracle时常会从磁盘中读取一些数据块到内存中。也就是说你在查询某些字段时,Oracle是把表中一整行的数据读取到内存当中,然后再从头到尾扫描你需要的字段。并非只读取你查询的那几个字段。
因为Oracle有缓存机制,第一次执行的数据会被缓存在内存中,当下次被访问时就不会去磁盘中加载。
在Oracle中选择执行计划,是根据优化器来决定的。而优化器是基于两种方式进行计算的。一种是规则,另一种是成本。在Oracle 11g当中,Oracle默认采用的优化策略是成本(Cost)。关于优化器
-
COUNT(1)和COUNT(*)的花费其实是一致的;
-
COUNT(*)是Oracle中的聚合函数,用于统计结果集的行数。
-
Oracle是一行行读取数据,并且在访问字段的时候是根据表中字段的顺序从左往右访问。所以COUNT(字段)或查询语句的字段在表中的顺序越靠左访问速度越快。
三、COUNT(1)、COUNT(*)、COUNT(字段)比较
COUNT(1)和COUNT(*)都会对全表进行扫描,统计所有记录的条数,包括那些为NULL的记录,因此,它们的效率可以说是相差无几。
而COUNT(字段)则与前两者不同,它会统计该字段不为null的记录条数。
总结对比:
- COUNT(1)、COUNT(*)、COUNT(rowid)这三种使用方式的统计的行数量都会包括null行。
- COUNT(字段)这种方式统计的行数不会包括字段值为NULL的值。
- 若查询表只有一个字段,则COUNT(*)最快;
- 若查询表无主键,则COUNT(1)比COUNT(*)快;
- 若查询表有主键,主键作为计算条件,则COUNT(主键)效率最高;
- 若查询表有主键,oracle优化策略,COUNT( * )会自动会优化指定到主键字段。因此:COUNT(1)和COUNT( * )基本没有差别。
- DISTINCT COUNT(*)返回总行数,去除重复且不含NULL值。