总有人说在面试时会被问COUNT(*)、COUNT(1)哪个快?
这次就来说说我的理解。
COUNT有三种格式:
⊙ COUNT(*)
COUNT(*)可以返回表中行的数量,包括重复的行和任意列中部分包含有空值的行。
⊙ COUNT(expr)
返回由expr标识的列中非空值的数量
⊙ COUNT(DISTINCT expr)
返回由expr标识的列中非空值的不重复值的数量
实验一下,看结果更直观:
先创建表,加入三条数据

分别执行查询,看看结果理解不

知道了COUNT的格式,下面来看看这个实验:
创建一张表,并加入测试数据。
并在object_id 创建一个索引

查看表结构,确认object_id 可为空

打开查看执行计划,执行Select count(*) from t;
走了全表扫描,如果一个表很大,全表扫描一下 很消耗资源。

执行Select count(1) from t;
和count(*) 一样 也是全表扫描。

再执行一下Select count(OBJECT_ID) from t;
走了索引扫描

那为什么会走索引不走全表扫描呢 ?
我们知道 count(列) 是不会统计列的NULL值的
而且索引里面也不会记录空值
所以我们可以走索引去计算
回看两个执行计划的cost,看索引扫描成本才26,比155少了很多。
继续试验。
把object_id列 修改为不可为空的

再执行Select count(*) from t;
查看count(*)的执行计划,这次走了索引
因为这个字段是NOT NULL,所以它的索引的条数 和记录的总条数是一样

执行Select count(1) from t;
结果也是一样

听到有人说count(1) 比count(*)性能好
通过咱们刚才的实验来看Count(1)和count(*)其实几乎没有什么区别。
小结一下:
COUNT(列名),能用上索引。
COUNT(*)、COUNT(1),如果索引列定义为非空,则能用上,否则用不上。
COUNT(*)与COUNT(1)没有区别。
别急着记结论,往下看
创建了一个t3表,只有object_id一列
我们创建了索引,并把这列修改为NOT NULL

我们执行一下 select count(*) from t3;
竟然不走索引

迷糊不,刚背完的结论怎么不成立了呢?
其实道理很简单:
索引要记录一列的值和物理地址
比表还多了个物理地址这一个东东
使得索引的总体积变成行数*(列的长度+物理地址的长度)
那这样算的话 索引是不是比表还要大了
表存放了10个数据块 你索引都存放了20个数据块
那我肯定是扫描这10个数据块更好
Oracle也是这么想的,所以优化器权衡下选择了全表检索。
所以在索引比全表快的前提下,之前的小结的部分才成立。




