1 表行计数器 说明
默认情况下,DM 达梦数据库count() 是秒回结果的,不受表中实际行数的影响,执行select count() 都能立即返回正确的结果。因为达梦数据库的count(*)操作不需要执行全表扫描,直接读取表行计数器的结果。
这个表行计数器实际上是表的一个存储属性,在创建表时可以指定是否启用表行计数器。默认为启动,可以配置为如下2个值:
WITH COUNTER:默认值,在表上维护当前表内的行数;
WITHOUT COUNTER:表上只维护一个非实时的大概的行数;
如果表启用了WITH COUNTER 属性, SELECT COUNT(*)时服务器直接取行数返回即可,可以快速响应;
如果表是 WITHOUT COUNTER 属性,服务器需要先扫描 B 树获取行数返回后才能响应。
COUNTER 属性可以通过alter table语句直接进行修改。
2 测试
2.1 创建默认启用counter的表cndba
[dave@www.cndba.cn ~]$ disql SYSDBA/SYSDBA
服务器[LOCALHOST:5236]:处于普通打开状态
登录使用时间: 12.679(毫秒)
disql V8
SQL> create table cndba(id int,website varchar(50));
操作已执行
已用时间: 9.588(毫秒). 执行号:3281.
SQL> insert into cndba values(1,'https://www.cndba.cn/dave');
影响行数 1
已用时间: 1.908(毫秒). 执行号:3282.
SQL> commit;
操作已执行
已用时间: 1.376(毫秒). 执行号:3283.
SQL>
查看此时的执行计划
SQL> explain select count(*) from cndba;
1 #NSET2: [0, 1, 0]
2 #PRJT2: [0, 1, 0]; exp_num(1), is_atom(FALSE)
3 #FAGR2: [0, 1, 0]; sfun_num(1),
已用时间: 29.509(毫秒). 执行号:0.
SQL>
2.2 创建没有启用counter的表cndba2
SQL> create table cndba2(id int,website varchar(50)) storage(without counter);
操作已执行
已用时间: 5.633(毫秒). 执行号:3284.
SQL> insert into cndba2 values(2,'https://www.cndba.cn/dave');
影响行数 1
已用时间: 2.107(毫秒). 执行号:3285.
SQL> commit;
操作已执行
已用时间: 1.856(毫秒). 执行号:3286.
SQL> explain select count(*) from cndba2;
1 #NSET2: [0, 1, 0]
2 #PRJT2: [0, 1, 0]; exp_num(1), is_atom(FALSE)
3 #AAGR2: [0, 1, 0]; grp_num(0), sfun_num(1) slave_empty(0)
4 #CSCN2: [0, 1, 0]; INDEX33555492(CNDBA2)
已用时间: 1.307(毫秒). 执行号:0.
SQL>
2.3 对比
2.3.1 查看表的定义语句
启用表行计数器:
[dave@www.cndba.cn Code]# drz getddl table cndba SYSDBA
*****************DDL SQL******************
CREATE TABLE "SYSDBA"."CNDBA"
(
"ID" INT,
"WEBSITE" VARCHAR(50)) STORAGE(ON "MAIN", CLUSTERBTR) ;
[dave@www.cndba.cn Code]#
未启用表行计数器:
[dave@www.cndba.cn Code]# drz getddl table cndba SYSDBA
*****************DDL SQL******************
CREATE TABLE "SYSDBA"."CNDBA2"
(
"ID" INT,
"WEBSITE" VARCHAR(50)) STORAGE(ON "MAIN", CLUSTERBTR, WITHOUT COUNTER) ;
[dave@www.cndba.cn Code]#
2.3.2 执行计划的操作符
启用counter:
2 #PRJT2: [0, 1, 0]; exp_num(1), is_atom(FALSE)
3 #FAGR2: [0, 1, 0]; sfun_num(1),
FAGR2 表示:快速聚集,如果没有 where 条件,且取 count(*), 或者基于索引的 MAX/MIN 值,则可以快速取得集函数的值
未启用counter:
2 #PRJT2: [0, 1, 0]; exp_num(1), is_atom(FALSE)
3 #AAGR2: [0, 1, 0]; grp_num(0), sfun_num(1) slave_empty(0)
4 #CSCN2: [0, 1, 0]; INDEX33555492(CNDBA2)
AAGR2表示:简单聚集
CSCN2表示:聚集索引扫描
2.4 Counter 状态切换
将cndba 改成不启用counter:
SQL> alter table cndba without counter;
操作已执行
已用时间: 9.653(毫秒). 执行号:3291.
SQL>
[dave@www.cndba.cn Code]# drz getddl table cndba SYSDBA
*****************DDL SQL******************
CREATE TABLE "SYSDBA"."CNDBA"
(
"ID" INT,
"WEBSITE" VARCHAR(50)) STORAGE(ON "MAIN", CLUSTERBTR, WITHOUT COUNTER) ;
将cndba2 改成启用counter:
SQL> alter table cndba2 with counter;
操作已执行
已用时间: 5.636(毫秒). 执行号:3294.
SQL>
[dave@www.cndba.cn Code]# drz getddl table cndba2 SYSDBA
*****************DDL SQL******************
CREATE TABLE "SYSDBA"."CNDBA2"
(
"ID" INT,
"WEBSITE" VARCHAR(50)) STORAGE(ON "MAIN", CLUSTERBTR) ;
2.5 Count(*) 时间对比
2.5.1 启用counter
SQL> create table t1 as select * from sysobjects;
操作已执行
已用时间: 11.657(毫秒). 执行号:3297.
SQL> insert into t1 select * from t1;
影响行数 1399
已用时间: 28.383(毫秒). 执行号:3298.
SQL> insert into t1 select * from t1;
影响行数 2798
已用时间: 14.120(毫秒). 执行号:3299.
SQL> insert into t1 select * from t1;
影响行数 5596
已用时间: 21.753(毫秒). 执行号:3300.
SQL> commit;
操作已执行
已用时间: 1.950(毫秒). 执行号:3301.
SQL> select count(*) from t1;
行号 COUNT(*)
---------- --------------------
1 11192
已用时间: 1.902(毫秒). 执行号:3302.
查询11192 花费1.902 毫秒。
2.5.2 未启用counter
SQL> create table t2 as select * from sysobjects where 1=2;
操作已执行
已用时间: 7.219(毫秒). 执行号:3303.
SQL> alter table t2 without counter;
操作已执行
已用时间: 7.715(毫秒). 执行号:3304.
SQL> insert into t2 select * from t1;
影响行数 11192
已用时间: 31.559(毫秒). 执行号:3305.
SQL> commit;
操作已执行
已用时间: 1.500(毫秒). 执行号:3306.
SQL> select count(*) from t2;
行号 COUNT(*)
---------- --------------------
1 11192
已用时间: 2.608(毫秒). 执行号:3307.
SQL>
查询11192 花费2.608 毫秒。
我们这里仅仅是1w多条数据,如果是上千万级别的记录数,那么时间差距就会更明显一些。
版权声明:本文为博主原创文章,未经博主允许不得转载。