目录
前言
Oracle中的统计COUNT(*)和COUNT(1)的效率比较,一直以来都是觉得COUNT(1)会比COUNT(*)快一些。至于为什么,我个人以前总觉得*这个符号会将Oracle中所有的字段记录会返回回来,而COUNT(1)只是统计了1的个数,相对比下就自认为COUNT(1)要快一些。然而有一次去参加客户方的一项数据开发时,他们一篇文档中写着COUNT(*)反而要比COUNT(1)快!这严重地打破了之前的认知。基于这个疑问,就尝试写了一下这篇文章,来探讨一下COUNT(1)和COUNT(*)的效率哪个快?
以下是本篇文章正文内容,下面案例可供参考
一、Oracle的存储机制
众所周知,Oracle是关系型数据库。跟Hbase等非关系型数据库不同的一点在于它的存储形式是采用行式存储的。行式存储也就是将表中的数据一行行的写入数据块。而数据块是Oracle的最小单位。每次我们在查询数据的时候,Oracle时常会从磁盘中读取一些数据块到内存中。也就是说你在查询某些字段时,Oracle是把表中一整行的数据读取到内存当中,然后再从头到尾扫描你需要的字段。并非只读取你查询的那几个字段。
二、COUNT(*)与COUNT(字段)的比较
1.COUNT 表中各个字段的比较
如上面所说,Oracle是一行行读取数据,并且在访问字段的时候是根据表中字段的顺序从左往右访问。所以字段在表中的顺序越靠左访问速度越快。为了验证这个设想,进行了如下实验:
/*
* 步骤1
* 目的:创建一张21个字段的的表
* 大小:1W条记录
*/
CREATE TABLE TMP_TEST_COUNT AS --创建表
SELECT LEVEL AS ID --序号
,CHR(65 + MOD(LEVEL, 26)) AS TEXT1 --字母,用ASCII计算而来
,CHR(65 + MOD(LEVEL, 26)) AS TEXT2
,CHR(65 + MOD(LEVEL, 26)) AS TEXT3
,CHR(65 + MOD(LEVEL, 26)) AS TEXT4
,CHR(65 + MOD(LEVEL, 26)) AS TEXT5
,CHR(65 + MOD(LEVEL, 26)) AS TEXT6
,CHR(65 + MOD(LEVEL, 26)) AS TEXT7
,CHR(65 + MOD(LEVEL, 26)) AS TEXT8
,CHR(65 + MOD(LEVEL, 26)) AS TEXT9
,CHR(65 + MOD(LEVEL, 26)) AS TEXT10
,CHR(65 + MOD(LEVEL, 26)) AS TEXT11
,CHR(65 + MOD(LEVEL, 26)) AS TEXT12
,CHR(65 + MOD(LEVEL, 26)) AS TEXT13
,CHR(65 + MOD(LEVEL, 26)) AS TEXT14
,CHR(65 + MOD(LEVEL, 26)) AS TEXT15
,CHR(65 + MOD(LEVEL, 26)) AS TEXT16
,CHR(65 + MOD(LEVEL, 26)) AS TEXT17
,CHR(65 + MOD(LEVEL, 26)) AS TEXT18
,CHR(65 + MOD(LEVEL, 26)) AS TEXT19
,CHR(65 + MOD(LEVEL, 26)) AS TEXT20
FROM DUAL
CONNECT BY LEVEL <= 10000;
/*
*步骤2
*目的:手动获取表的信息,为了后续SQL执行能有一个正确的执行计划
*/
CALL DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=>RPT, TABNAME=>'TMP_TEST_COUNT');
/*
*步骤3
*目的:统计各个字段统计的时长
*/
DECLARE
L_DUMMY PLS_INTEGER;
L_START PLS_INTEGER;
L_STOP PLS_INTEGER;
L_SQL VARCHAR2(100);
BEGIN
FOR I IN 1 .. 20 LOOP
L_SQL := 'SELECT COUNT(TEXT' || I || ') FROM TMP_TEST_COUNT';
--因为Oracle有缓存机制,第一次执行的数据会被缓存在内存中,当下次被访问时就不会去磁盘中加载。为了精准测试先加载数据
EXECUTE IMMEDIATE L_SQL;
L_START :=