count(*),count(1)和count(主键)的区别

Ruben_yu 2009-08-25 08:06:18
count(*),count(1)和count(主键)的区别到底是什么,有谁能回答。谢谢
...全文
45208 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
影子鑫 2011-12-19
  • 打赏
  • 举报
回复
学习了~

3楼貌似很强大~
oracle_louis 2009-09-03
  • 打赏
  • 举报
回复
这似乎是个永恒的话题
winganson 2009-09-03
  • 打赏
  • 举报
回复
学习了
zzzzzyyy 2009-09-02
  • 打赏
  • 举报
回复
小问题也不能放过,计算机里的东西说不准,不注意的小问题也可能成为大问题,学习了,一点一滴积累
-无-为- 2009-09-02
  • 打赏
  • 举报
回复

SQL> select /*+ FIRST_ROWS */ count(*) from emp,emp,emp,emp,emp,emp,emp;
已用时间: 00: 00: 00.04

执行计划
----------------------------------------------------------
Plan hash value: 2048615215

-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1786K (1)| 05:57:13 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | MERGE JOIN CARTESIAN | | 105M| 1786K (1)| 05:57:13 |
| 3 | MERGE JOIN CARTESIAN | | 7529K| 127K (1)| 00:25:32 |
| 4 | MERGE JOIN CARTESIAN | | 537K| 9121 (1)| 00:01:50 |
| 5 | MERGE JOIN CARTESIAN | | 38416 | 657 (1)| 00:00:08 |
| 6 | MERGE JOIN CARTESIAN | | 2744 | 51 (0)| 00:00:01 |
| 7 | MERGE JOIN CARTESIAN | | 196 | 6 (0)| 00:00:01 |
| 8 | INDEX FULL SCAN | PK_EMP | 14 | 1 (0)| 00:00:01 |
| 9 | BUFFER SORT | | 14 | 5 (0)| 00:00:01 |
| 10 | INDEX FAST FULL SCAN| PK_EMP | 14 | 0 (0)| 00:00:01 |
| 11 | BUFFER SORT | | 14 | 51 (0)| 00:00:01 |
| 12 | INDEX FAST FULL SCAN | PK_EMP | 14 | 0 (0)| 00:00:01 |
| 13 | BUFFER SORT | | 14 | 657 (1)| 00:00:08 |
| 14 | INDEX FAST FULL SCAN | PK_EMP | 14 | 0 (0)| 00:00:01 |
| 15 | BUFFER SORT | | 14 | 9120 (1)| 00:01:50 |
| 16 | INDEX FAST FULL SCAN | PK_EMP | 14 | 0 (0)| 00:00:01 |
| 17 | BUFFER SORT | | 14 | 127K (1)| 00:25:32 |
| 18 | INDEX FAST FULL SCAN | PK_EMP | 14 | 0 (0)| 00:00:01 |
| 19 | BUFFER SORT | | 14 | 1786K (1)| 05:57:13 |
| 20 | INDEX FAST FULL SCAN | PK_EMP | 14 | 0 (0)| 00:00:01 |
-------------------------------------------------------------------------------

SQL> select /*+ FIRST_ROWS */ count(1) from emp,emp,emp,emp,emp,emp,emp;
已用时间: 00: 00: 00.03

执行计划
----------------------------------------------------------
Plan hash value: 2048615215

-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1786K (1)| 05:57:13 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | MERGE JOIN CARTESIAN | | 105M| 1786K (1)| 05:57:13 |
| 3 | MERGE JOIN CARTESIAN | | 7529K| 127K (1)| 00:25:32 |
| 4 | MERGE JOIN CARTESIAN | | 537K| 9121 (1)| 00:01:50 |
| 5 | MERGE JOIN CARTESIAN | | 38416 | 657 (1)| 00:00:08 |
| 6 | MERGE JOIN CARTESIAN | | 2744 | 51 (0)| 00:00:01 |
| 7 | MERGE JOIN CARTESIAN | | 196 | 6 (0)| 00:00:01 |
| 8 | INDEX FULL SCAN | PK_EMP | 14 | 1 (0)| 00:00:01 |
| 9 | BUFFER SORT | | 14 | 5 (0)| 00:00:01 |
| 10 | INDEX FAST FULL SCAN| PK_EMP | 14 | 0 (0)| 00:00:01 |
| 11 | BUFFER SORT | | 14 | 51 (0)| 00:00:01 |
| 12 | INDEX FAST FULL SCAN | PK_EMP | 14 | 0 (0)| 00:00:01 |
| 13 | BUFFER SORT | | 14 | 657 (1)| 00:00:08 |
| 14 | INDEX FAST FULL SCAN | PK_EMP | 14 | 0 (0)| 00:00:01 |
| 15 | BUFFER SORT | | 14 | 9120 (1)| 00:01:50 |
| 16 | INDEX FAST FULL SCAN | PK_EMP | 14 | 0 (0)| 00:00:01 |
| 17 | BUFFER SORT | | 14 | 127K (1)| 00:25:32 |
| 18 | INDEX FAST FULL SCAN | PK_EMP | 14 | 0 (0)| 00:00:01 |
| 19 | BUFFER SORT | | 14 | 1786K (1)| 05:57:13 |
| 20 | INDEX FAST FULL SCAN | PK_EMP | 14 | 0 (0)| 00:00:01 |
-------------------------------------------------------------------------------
非萨范德萨发 2009-09-01
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 jdsnhan 的回复:]
这个问题其实很无聊,莫要钻牛角尖,从count(*),count(id)等去调优,有些得不偿失。

UP.
perliu 2009-09-01
  • 打赏
  • 举报
回复
上面的回答都很详细了,效率上的问题不用考虑太多,count(*),count(1)和count(主键)都没错,结合实际数据库运行一下,选择你合适的就可以。

最关键是在你统计个数的时候是否需要考虑到有空值的情况,count(主键)肯定没有空值,但是对于一个没有主键的表或者 count(任意字段)时, count(*)能取出含有空值的所有记录数,count(任意字段)不含空值。

6楼、13楼、14楼讲的都很不错了。
buffon1260 2009-08-31
  • 打赏
  • 举报
回复
学习了
Ruben_yu 2009-08-31
  • 打赏
  • 举报
回复
谢谢大家了
zehochux 2009-08-31
  • 打赏
  • 举报
回复
学习了
woshifenmi 2009-08-31
  • 打赏
  • 举报
回复
当表的数据量大些时,对表作分析之后,使用count(1)还要比使用count(*)用时多了!

从执行计划来看,count(1)和count(*)的效果是一样的。
但是在表做过分析之后,count(1)会比count(*)的用时少些(1w以内数据量),不过差不了多少。
这个也与表的记录数多少有关!如果1w以外的数据量,做过表分析之后,反而count(1)的用时比count(*)多了。

另外,当数据量达到10w多的时候,使用count(1)要比使用count(*)的用时稍微少点!

如果你的数据表没有主键,那么count(1)比count(*)快
如果有主键的话,那主键(联合主键)作为count的条件也比count(*)要快
如果你的表只有一个字段的话那count(*)就是最快的啦
count(*) count(1) 两者比较。主要还是要count(1)所相对应的数据字段。
如果count(1)是聚索引,id,那肯定是count(1)快。但是差的很小的。
因为count(*),自动会优化指定到那一个字段。所以没必要去count(1),用count(*),sql会帮你完成优化的
因此:count(1)和count(*)基本没有差别!

sql调优,主要是考虑降低:consistent gets和physical reads的数量。
cab1225 2009-08-31
  • 打赏
  • 举报
回复
经常有人说count(1)比count(*)快。实际上是这样吗?不是的,作为数据库的衡量性能的逻辑读来说,是没有差异的。但是在实际的多次反复测试中,我们可以来对比看看真实状况。

SQL> create table t as select * from all_objects;
Table created.
SQL> select count(*) from all_objects;
COUNT(*)
----------
3789
SQL> desc t
Name Null? Type
----------------------------------------- -------- ----------------------------
OWNER NOT NULL VARCHAR2(30)
OBJECT_NAME NOT NULL VARCHAR2(30)
SUBOBJECT_NAME VARCHAR2(30)
OBJECT_ID NOT NULL NUMBER
DATA_OBJECT_ID NUMBER
OBJECT_TYPE VARCHAR2(18)
CREATED NOT NULL DATE
LAST_DDL_TIME NOT NULL DATE
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)

先 delete statistics , 各方式分别求 1000次 count
然后 analyze table ,各方式分别求 1000次 count
然后做个时间对比

服务器无外界干扰的情况下的反复测试的结果如下
declare
n_count number;
n_time0 number;
n_time1 number;
n_time2 number;
n_time3 number;
n_time4 number;

begin
execute immediate'analyze table t delete statistics';


select count(*) into n_count from t;

n_time0 := dbms_utility.get_time;
for i in 1..1000 loop
select /*+index(t t_index)*/ count(*) into n_count from t;
end loop;

n_time1 := dbms_utility.get_time;
for i in 1..1000 loop
select count(*) into n_count from t;
end loop;

n_time2 := dbms_utility.get_time;

for i in 1..1000 loop
select count(1) into n_count from t;
end loop;
n_time3 := dbms_utility.get_time;
for i in 1..1000 loop
select count(rowid) into n_count from t;
end loop;
n_time4 := dbms_utility.get_time;

dbms_output.put_line('the count of the table T : '||to_char(n_count));
dbms_output.put_line('before analyze ,loop 1000,/*+hints*/count(*) :'||to_char(n_time1 - n_time0 ));
dbms_output.put_line('before analyze ,loop 1000,count(*) :'||to_char(n_time2 - n_time1));
dbms_output.put_line('before analyze ,loop 1000,count(1) :'||to_char(n_time3 - n_time2));
dbms_output.put_line('before analyze ,loop 1000,count(rowid) :'||to_char(n_time4 - n_time3));

execute immediate'analyze table t compute statistics';

select count(*) into n_count from t;
n_time1 := dbms_utility.get_time;
for i in 1..1000 loop
select count(*) into n_count from t;
end loop;

n_time2 := dbms_utility.get_time;

for i in 1..1000 loop
select count(1) into n_count from t;
end loop;
n_time3 := dbms_utility.get_time;
for i in 1..1000 loop
select count(rowid) into n_count from t;
end loop;
n_time4 := dbms_utility.get_time;

dbms_output.put_line('the count of the table T : '||to_char(n_count));
dbms_output.put_line('after analyze ,loop 1000,count(*) :'||to_char(n_time2 - n_time1));
dbms_output.put_line('after analyze ,loop 1000,count(1) :'||to_char(n_time3 - n_time2));
dbms_output.put_line('after analyze ,loop 1000,count(rowid) :'||to_char(n_time4 - n_time3));

end;
the count of the table T : 3789
before analyze ,loop 1000,/*+hints*/count(*) :71
before analyze ,loop 1000,count(*) :63
before analyze ,loop 1000,count(1) :91
before analyze ,loop 1000,count(rowid) :88
the count of the table T : 3789
after analyze ,loop 1000,count(*) :28
after analyze ,loop 1000,count(1) :28
after analyze ,loop 1000,count(rowid) :79
PL/SQL procedure successfully completed.
SQL> /
the count of the table T : 3789
before analyze ,loop 1000,/*+hints*/count(*) :72
before analyze ,loop 1000,count(*) :61
before analyze ,loop 1000,count(1) :88
before analyze ,loop 1000,count(rowid) :85
the count of the table T : 3789
after analyze ,loop 1000,count(*) :28
after analyze ,loop 1000,count(1) :27
after analyze ,loop 1000,count(rowid) :82
PL/SQL procedure successfully completed.

从这里我们可以看出在时间的对比上,同样通过全表扫描和走索引,除了count(rowid)在走索引的时候明显慢外,其他情况下差异都不是很大,很明显,对于这样的求和来说,我们使用 count(*) 是没有什么不好的,count(1)更快纯粹是一个谬论。
sinohang 2009-08-31
  • 打赏
  • 举报
回复
学习了
csuxp2008 2009-08-26
  • 打赏
  • 举报
回复
学习了
hailang1118 2009-08-25
  • 打赏
  • 举报
回复
这个问题就是问你什么时候Oracle容易走表查询,什么时候Oracle容易走INDEX查询。
实际应用中,你得看实际情况,没准这个表没有唯一键索引呢?在CBO的情况下,统计情报不准确呢?没准。。。

这种问题会出现好多版本的回答。测试环境不同结果也不一样,你随便键个表,看看它们的执行计划,就能看出他们的区别了。

CSDN不能连续回复3次,害我等了好长时间楼上回复。。。
jdsnhan 2009-08-25
  • 打赏
  • 举报
回复
这个问题其实很无聊,莫要钻牛角尖,从count(*),count(id)等去调优,有些得不偿失。

给你一些比较数据,但愿能有一些体会。

SQL> select count(*) from ysgl_compile_reqsub;

COUNT(*)
----------
5288265

已用时间: 00: 00: 07.51
SQL> select count(1) from ysgl_compile_reqsub;

COUNT(1)
----------
5288265

已用时间: 00: 00: 00.68
SQL> select count(id) from ysgl_compile_reqsub;

COUNT(ID)
----------
5288265

已用时间: 00: 00: 00.68
SQL> select count(rowid) from ysgl_compile_reqsub;

COUNT(ROWID)
------------
5288265

已用时间: 00: 00: 01.01
SQL> select count(rowid) from ysgl_vdata_his;

COUNT(ROWID)
------------
5299458

已用时间: 00: 00: 09.98
SQL> select count(*) from ysgl_vdata_his;

COUNT(*)
----------
5299458

已用时间: 00: 00: 00.93
SQL> select count(1) from ysgl_vdata_his;

COUNT(1)
----------
5299458

已用时间: 00: 00: 00.71
SQL> select count(1) from ysgl_excelbasic;

COUNT(1)
----------
3755052

已用时间: 00: 00: 04.60
SQL> select count(*) from ysgl_excelbasic;

COUNT(*)
----------
3755052

已用时间: 00: 00: 00.50
SQL>
hailang1118 2009-08-25
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 c4313848 的回复:]
http://bitirainy.itpub.net/post/330/1914
[/Quote]
应该是引用这个。。。
hailang1118 2009-08-25
  • 打赏
  • 举报
回复
[Quote=引用楼主 ruben_yu 的回复:]
count(*),count(1)和count(主键)的区别到底是什么,有谁能回答。谢谢
[/Quote]
这个帖子里面的楼主的测试数据,不知道在什么情况下。
我在300万业务数据上测试的结果是count(ROWID),count(1),count(主键)这个三种情况速度差不多,
count(*)这种明显慢,察看执行计划,COUNT(*)时候走的是全表查询。
hailang1118 2009-08-25
  • 打赏
  • 举报
回复
补充一下。
不考虑Null的情况
count(1)和count(主键) 这两个只扫描主键Index就可以得到数据,
count(*)是扫描表的。
所以count(1)和count(主键)这两个效率高。
还有一种写法是count(ROWID)这也是只扫描Index的,效率高。
Dave 2009-08-25
  • 打赏
  • 举报
回复
如果null参与聚集运算,则除count(*)之外其它聚集函数都忽略null.

如:
ID DD
1 e
2 null
select count(*) from table --结果是2
select count(DD) from table ---结果是1

有说count(1)效率高,感觉差不多..没啥区别
加载更多回复(1)

17,082

社区成员

发帖
与我相关
我的任务
社区描述
Oracle开发相关技术讨论
社区管理员
  • 开发
  • Lucifer三思而后行
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧