博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
count(*)、count(val)和count(1)的解释
阅读量:6801 次
发布时间:2019-06-26

本文共 11673 字,大约阅读时间需要 38 分钟。

一、关于count的一些谣言:

    1、count(*)比count(val)更慢!项目组必须用count(val),不准用count(*),谁用扣谁钱!

    2、count(*)用不到索引,count(val)才能用到。

    3、count(*)是统计出全表的记录,是吞吐量的操作,肯定用不到索引。

    4、count(1)比count(*)的速度快。

二、验证count(*)和count(val)

    1、首先创建一个表,使用count(*)和count(val)查询比较:

----删除echo表---- SQL> drop table echo purge;drop table echo purge           *第 1 行出现错误:ORA-00942: 表或视图不存在----创建一张echo的测试表----SQL> create table echo as select * from dba_objects;表已创建。SQL> update echo set object_id =  rownum;已更新72509行。SQL> commit;提交完成。SQL> set timing onSQL> set linesize 100SQL> set autotrace onSQL> select count(*) from echo;  COUNT(*)----------     72509已用时间:  00: 00: 00.01执行计划----------------------------------------------------------Plan hash value: 99109176-------------------------------------------------------------------| Id  | Operation       | Name | Rows  | Cost (%CPU)| Time      |-------------------------------------------------------------------|   0 | SELECT STATEMENT   |      |    1 |   290   (1)| 00:00:04 ||   1 |  SORT AGGREGATE    |      |    1 |           |      ||   2 |   TABLE ACCESS FULL| ECHO | 80064 |   290   (1)| 00:00:04 |-------------------------------------------------------------------Note-----   - dynamic sampling used for this statement (level=2)统计信息----------------------------------------------------------      4  recursive calls      0  db block gets       1265  consistent gets      0  physical reads      11060  redo size    425  bytes sent via SQL*Net to client    415  bytes received via SQL*Net from client      2  SQL*Net roundtrips to/from client      0  sorts (memory)      0  sorts (disk)      1  rows processedSQL> select count(*) from echo;  COUNT(*)----------     72509已用时间:  00: 00: 00.01执行计划----------------------------------------------------------Plan hash value: 99109176-------------------------------------------------------------------| Id  | Operation       | Name | Rows  | Cost (%CPU)| Time      |-------------------------------------------------------------------|   0 | SELECT STATEMENT   |      |    1 |   290   (1)| 00:00:04 ||   1 |  SORT AGGREGATE    |      |    1 |           |      ||   2 |   TABLE ACCESS FULL| ECHO | 80064 |   290   (1)| 00:00:04 |-------------------------------------------------------------------Note-----   - dynamic sampling used for this statement (level=2)统计信息----------------------------------------------------------      0  recursive calls      0  db block gets       1038  consistent gets      0  physical reads      0  redo size    425  bytes sent via SQL*Net to client    415  bytes received via SQL*Net from client      2  SQL*Net roundtrips to/from client      0  sorts (memory)      0  sorts (disk)      1  rows processedSQL> select count(object_id) from echo;COUNT(OBJECT_ID)----------------       72509已用时间:  00: 00: 00.01执行计划----------------------------------------------------------Plan hash value: 99109176---------------------------------------------------------------------------| Id  | Operation       | Name | Rows  | Bytes | Cost (%CPU)| Time      |---------------------------------------------------------------------------|   0 | SELECT STATEMENT   |      |    1 |    13 |   290   (1)| 00:00:04 ||   1 |  SORT AGGREGATE    |      |    1 |    13 |           |      ||   2 |   TABLE ACCESS FULL| ECHO | 80064 |  1016K|   290   (1)| 00:00:04 |---------------------------------------------------------------------------Note-----   - dynamic sampling used for this statement (level=2)统计信息----------------------------------------------------------      4  recursive calls      0  db block gets       1112  consistent gets      0  physical reads      0  redo size    433  bytes sent via SQL*Net to client    415  bytes received via SQL*Net from client      2  SQL*Net roundtrips to/from client      0  sorts (memory)      0  sorts (disk)      1  rows processedSQL> select count(object_id) from echo;COUNT(OBJECT_ID)----------------       72509已用时间:  00: 00: 00.01执行计划----------------------------------------------------------Plan hash value: 99109176---------------------------------------------------------------------------| Id  | Operation       | Name | Rows  | Bytes | Cost (%CPU)| Time      |---------------------------------------------------------------------------|   0 | SELECT STATEMENT   |      |    1 |    13 |   290   (1)| 00:00:04 ||   1 |  SORT AGGREGATE    |      |    1 |    13 |           |      ||   2 |   TABLE ACCESS FULL| ECHO | 80064 |  1016K|   290   (1)| 00:00:04 |---------------------------------------------------------------------------Note-----   - dynamic sampling used for this statement (level=2)统计信息----------------------------------------------------------      0  recursive calls      0  db block gets       1038  consistent gets      0  physical reads      0  redo size    433  bytes sent via SQL*Net to client    415  bytes received via SQL*Net from client      2  SQL*Net roundtrips to/from client      0  sorts (memory)      0  sorts (disk)      1  rows processed

     从上面的执行计划可以看出count(*)和count(val)是一样快的。

    2、建立索引做比较

SQL> create index idx_object_id on echo(object_id);索引已创建。已用时间:  00: 00: 05.69SQL> select count(*) from echo;  COUNT(*)----------     72509已用时间:  00: 00: 00.05执行计划----------------------------------------------------------Plan hash value: 99109176-------------------------------------------------------------------| Id  | Operation       | Name | Rows  | Cost (%CPU)| Time      |-------------------------------------------------------------------|   0 | SELECT STATEMENT   |      |    1 |   290   (1)| 00:00:04 ||   1 |  SORT AGGREGATE    |      |    1 |           |      ||   2 |   TABLE ACCESS FULL| ECHO | 80064 |   290   (1)| 00:00:04 |-------------------------------------------------------------------Note-----   - dynamic sampling used for this statement (level=2)统计信息----------------------------------------------------------      5  recursive calls      0  db block gets       1113  consistent gets      0  physical reads      0  redo size    425  bytes sent via SQL*Net to client    415  bytes received via SQL*Net from client      2  SQL*Net roundtrips to/from client      0  sorts (memory)      0  sorts (disk)      1  rows processedSQL> select count(object_id) from echo;COUNT(OBJECT_ID)----------------       72509已用时间:  00: 00: 00.08执行计划----------------------------------------------------------Plan hash value: 1131838604---------------------------------------------------------------------------------------| Id  | Operation          | Name          | Rows  | Bytes | Cost (%CPU)| Time     |---------------------------------------------------------------------------------------|   0 | SELECT STATEMENT      |           |     1 |    13 |    49    (0)| 00:00:01 ||   1 |  SORT AGGREGATE       |           |     1 |    13 |        |          ||   2 |   INDEX FAST FULL SCAN| IDX_OBJECT_ID | 80064 |  1016K|    49    (0)| 00:00:01 |---------------------------------------------------------------------------------------Note-----   - dynamic sampling used for this statement (level=2)统计信息----------------------------------------------------------      4  recursive calls      0  db block gets    244  consistent gets    161  physical reads      0  redo size    433  bytes sent via SQL*Net to client    415  bytes received via SQL*Net from client      2  SQL*Net roundtrips to/from client      0  sorts (memory)      0  sorts (disk)      1  rows processed

    哇,原来真的是用count(val)比count(*)要快啊,因为count(*)不能用到索引,而count(val)可以,真相真是如此吗?

    3、将object_id设置为非空

SQL> alter table echo modify object_id not null;表已更改。已用时间:  00: 00: 01.41SQL> select count(*) from echo;  COUNT(*)----------     72509已用时间:  00: 00: 00.00执行计划----------------------------------------------------------Plan hash value: 1131838604-------------------------------------------------------------------------------| Id  | Operation          | Name          | Rows  | Cost (%CPU)| Time     |-------------------------------------------------------------------------------|   0 | SELECT STATEMENT      |           |     1 |    49    (0)| 00:00:01 ||   1 |  SORT AGGREGATE       |           |     1 |        |          ||   2 |   INDEX FAST FULL SCAN| IDX_OBJECT_ID | 80064 |    49    (0)| 00:00:01 |-------------------------------------------------------------------------------Note-----   - dynamic sampling used for this statement (level=2)统计信息----------------------------------------------------------      0  recursive calls      0  db block gets    169  consistent gets      0  physical reads      0  redo size    425  bytes sent via SQL*Net to client    415  bytes received via SQL*Net from client      2  SQL*Net roundtrips to/from client      0  sorts (memory)      0  sorts (disk)      1  rows processedSQL> select count(object_id) from echo;COUNT(OBJECT_ID)----------------       72509已用时间:  00: 00: 00.01执行计划----------------------------------------------------------Plan hash value: 1131838604-------------------------------------------------------------------------------| Id  | Operation          | Name          | Rows  | Cost (%CPU)| Time     |-------------------------------------------------------------------------------|   0 | SELECT STATEMENT      |           |     1 |    49    (0)| 00:00:01 ||   1 |  SORT AGGREGATE       |           |     1 |        |          ||   2 |   INDEX FAST FULL SCAN| IDX_OBJECT_ID | 80064 |    49    (0)| 00:00:01 |-------------------------------------------------------------------------------Note-----   - dynamic sampling used for this statement (level=2)统计信息----------------------------------------------------------      0  recursive calls      0  db block gets    169  consistent gets      0  physical reads      0  redo size    433  bytes sent via SQL*Net to client    415  bytes received via SQL*Net from client      2  SQL*Net roundtrips to/from client      0  sorts (memory)      0  sorts (disk)      1  rows processed

--看来count(val)和count(*)其实一样快,如果索引列是非空的,count(*)可用到索引,此时一样快!真相真是如此吗?

其实两者根本没有可比性,性能比较首先考虑写法等价,这两个语句根本就不等价。

结论:

    其实优化器里的算法是这么玩的,列的偏移量决定性能,列越靠后,访问的开销越大。由于count(*)的算法与列偏移量无关,所以count(*)最快,count(最后列val)最慢。

    3、用实验验证上面的结论:

SQL> set serveroutput onSQL> set echo onSQL> drop table t purge;表已删除。----构造出有25个字段的表T----DECLARE  l_sql VARCHAR2(32767);BEGIN  l_sql := 'CREATE TABLE t (';  FOR i IN 1..25   LOOP    l_sql := l_sql || 'n' || i || ' NUMBER,';  END LOOP;  l_sql := l_sql || 'pad VARCHAR2(1000)) PCTFREE 10';  EXECUTE IMMEDIATE l_sql;END; 12  /PL/SQL 过程已成功完成。----将记录还有这个表T中填充----DECLARE  l_sql VARCHAR2(32767);BEGIN  l_sql := 'INSERT INTO t SELECT ';  FOR i IN 1..25  LOOP    l_sql := l_sql || '0,';  END LOOP;  l_sql := l_sql || 'NULL FROM dual CONNECT BY level <= 10000';  EXECUTE IMMEDIATE l_sql;  COMMIT;END; 13  /PL/SQL 过程已成功完成。execute dbms_stats.gather_table_stats(ownname=>user, tabname=>'t')SELECT num_rows, blocks FROM user_tables WHERE table_name = 'T';PL/SQL 过程已成功完成。SQL>   NUM_ROWS     BLOCKS---------- ----------     10000       80----以下动作观察执行速度,比较发现count(*)最快,count(最大列)最慢----SQL> DECLARE  l_dummy PLS_INTEGER;  l_start PLS_INTEGER;  l_stop PLS_INTEGER;  l_sql VARCHAR2(100);BEGIN  l_start := dbms_utility.get_time;  FOR j IN 1..1000  LOOP    EXECUTE IMMEDIATE 'SELECT count(*) FROM t' INTO l_dummy;  END LOOP;  l_stop := dbms_utility.get_time;  dbms_output.put_line((l_stop-l_start)/100); 14    FOR i IN 1..25  LOOP    l_sql := 'SELECT count(n' || i || ') FROM t';    l_start := dbms_utility.get_time;    FOR j IN 1..1000    LOOP      EXECUTE IMMEDIATE l_sql INTO l_dummy;    END LOOP;    l_stop := dbms_utility.get_time;    dbms_output.put_line((l_stop-l_start)/100);  END LOOP;END; 27  /.18.33.39.38.42.4.45.49.48.46.48.48.55.51.56.57.61.62.75.67.68.7.73.78.77.81PL/SQL 过程已成功完成。

三、验证count(*)和count(1)

    沿用TOM大师的解释:

 

转载地址:http://qmuwl.baihongyu.com/

你可能感兴趣的文章
arcEngine 10 C++ 坐标转换【坐标系的投影】
查看>>
Java6 WebService学习
查看>>
命名规则 : 匈牙利法则
查看>>
适用于单选的jQuery Auto-complete插件SelectToAutocomplete
查看>>
我的Windows 8下看漫画程序差不多可以用了
查看>>
rabbitmq使用__python客户端(消息接收者)
查看>>
如何实现一套鼠标键盘控制二台主机
查看>>
html5 手机页面
查看>>
Ubuntu 配置VNC以及使用VNC连接时,无法显示系统菜单栏,解决方法
查看>>
c# 如何通过反射 获取\设置属性值、
查看>>
分享:Apache OpenNLP 1.5.3 发布
查看>>
PCB_栅格大小设置
查看>>
在eclipse 的整个工程中查找字符串
查看>>
[转]Android中的Intent详细讲解
查看>>
电商也要懂的实体渠道实战知识zz
查看>>
命令行管理远程windows.(Remote Command Line On Windows)
查看>>
调用webservice使用URLConnection调用webservice
查看>>
父亲节例行吐槽
查看>>
c#动态创建ODBC数据源
查看>>
修改visual studio2010 的快捷键,使用ctrl+W 关闭当前文档
查看>>