达梦数据库COUNT(*)性能分析

本文通过实验展示了达梦数据库在COUNT(*)操作上的高效性能,尤其是在索引组织表存储形式下,即使数据量大幅增长,统计速度仍保持在0.2毫秒左右。通过对比堆表和关闭内部计数器的情况,揭示了达梦数据库内部计数器对COUNT(*)性能的影响。使用sp_tabledef等工具可以进一步了解和验证数据库状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

梁敬彬梁敬弘兄弟出品

达梦数据库在COUNT(*)操作上表现出色,本文通过实验数据展示并分析其性能特点。

一、实验现象:COUNT(*)的高性能表现

1.1 初始测试(约2800条记录)

drop table t purge;

create table t as select * from dba_objects;

SQL> insert into t select * from t;
影响行数 1401
已用时间: 32.849(毫秒). 执行号:256.

SQL> commit;
操作已执行
已用时间: 2.270(毫秒). 执行号:257.

SQL> select count(*) from t;
行号     COUNT(*)            
---------- --------------------
1          2802
已用时间: 0.239(毫秒). 执行号:288.

1.2 数据量增加后测试(约570万条记录)

SQL> insert into t select * from t;
影响行数 2869248
已用时间: 00:00:45.028. 执行号:289.

SQL> commit;
操作已执行
已用时间: 8.689(毫秒). 执行号:290.

SQL> select count(*) from t;
行号     COUNT(*)            
---------- --------------------
1          5738496
已用时间: 0.213(毫秒). 执行号:291.

关键观察:数据量增长超过1000倍(从2800条到570万条),而COUNT(*)执行时间几乎不变(保持在0.2毫秒左右)。

二、原理分析:内部计数器机制

原文推测达梦数据库的高效COUNT(*)与两个因素可能有关:

索引组织表结构:默认的表存储形式
内部计数器:表内部维护记录数量
2.1 验证索引组织表因素

通过创建堆表(NOBRANCH选项)测试:

SQL> drop table t purge;
操作已执行
已用时间: 30.886(毫秒). 执行号:295.

SQL> create table t STORAGE (NOBRANCH) as select * from dba_objects;
操作已执行

SQL> insert into t select * from t;
影响行数 2869248
已用时间: 00:00:20.234. 执行号:330.

SQL> commit;
操作已执行
已用时间: 769.113(毫秒). 执行号:331.

SQL> select count(*) from t;
行号     COUNT(*)            
---------- --------------------
1          5738496
已用时间: 0.299(毫秒). 执行号:332.

结论:堆表的COUNT(*)性能同样很高,说明高性能并非由索引组织表结构带来。

2.2 验证内部计数器因素

通过禁用计数器选项(WITHOUT COUNTER)测试:

create table t storage(without counter) as select * from dba_objects;

SQL> select count(*) from t;
行号     COUNT(*)            
---------- --------------------
1          2802
已用时间: 18.292(毫秒). 执行号:340.

SQL> insert into t select * from t;
影响行数 2869248
已用时间: 00:00:22.171. 执行号:371.

SQL> commit;
操作已执行
已用时间: 54.104(毫秒). 执行号:372.

SQL> select count(*) from t;
行号     COUNT(*)            
---------- --------------------
1          5738496
已用时间: 00:00:01.436. 执行号:373.

SQL> insert into t select * from t;
影响行数 5738496
已用时间: 00:00:23.270. 执行号:374.

SQL> commit;
操作已执行
已用时间: 16.629(毫秒). 执行号:375.

SQL> select count(*) from t;
行号     COUNT(*)            
---------- --------------------
1          11476992
已用时间: 00:00:03.256. 执行号:376.

关键观察:

禁用计数器后,初始COUNT()性能从0.2毫秒变为18.292毫秒
数据量增加到570万条时,耗时增至1.436秒
数据量增加到1147万条时,耗时增至3.256秒
性能随数据量呈线性下降趋势
结论:内部计数器是达梦数据库COUNT(
)高性能的关键因素。

2.3 查看表计数器状态

通过系统存储过程可查看表是否启用计数器:

SQL> sp_tabledef('LJB','T');
行号     COLUMN_VALUE
-------------------------------------------------------------------------------------------------------------------------------------------
1          CREATE TABLE "LJB"."T" (...) STORAGE(ON "MAIN", CLUSTERBTR, WITHOUT COUNTER);
已用时间: 172.222(毫秒). 执行号:377.

三、应用建议

基于实验结果,可得出以下应用建议:

默认使用计数器:达梦数据库默认启用计数器,这对COUNT(*)查询非常有利

特定场景禁用计数器:如果业务中很少使用COUNT(*)但频繁进行大批量更新操作,可考虑禁用计数器以提高写入性能

创建表时指定计数器选项:

-- 启用计数器(默认)
CREATE TABLE table_name (...);

-- 禁用计数器
CREATE TABLE table_name (...) STORAGE(WITHOUT COUNTER);

利用计数器特性优化查询:当需要获取表总行数时,优先使用简单的COUNT(*)而非带条件的查询

四、总结

达梦数据库通过内部计数器机制实现了高效的COUNT(*)操作,使其在数据量增长的情况下仍保持稳定的高性能。实验证明:

无论是索引组织表还是堆表,只要启用计数器,COUNT()性能都非常优异
禁用计数器后,COUNT(
)性能随数据量增长而线性下降
通过sp_tabledef存储过程可以查询表的计数器状态
这一特性使达梦数据库在需要频繁统计表行数的场景中具有显著优势,特别是对于大型表的统计操作,性能表现尤为突出。

在这里插入图片描述

国内一线知名数据库专家、畅销书《收获,不止Oracle》作者梁敬彬老师,做客【达梦会客厅】

达梦数据库知识总结链接贴

公众号:收获不止数据库

系列回顾
“大白话人工智能” 系列
“数据库拍案惊奇” 系列
“世事洞明皆学问” 系列

### 达梦数据库 COUNT 函数的使用方法 COUNT 是一种聚合函数,在达梦数据库中用于统计满足特定条件的记录数。它能够返回指定列中非 NULL 值的数量,或者当使用 `*` 时,则会计算表中的总行数。 以下是 COUNT 函数的基本语法: ```sql COUNT(expression) ``` 其中 `expression` 可以是一个具体的字段名或者是通配符 `*`。如果使用的是某个字段作为参数,那么只有该字段不为 NULL 的记录才会被计入总数;而如果是 `COUNT(*)`,则无论是否有 NULL 值都会计数所有的行[^1]。 #### 示例一:统计整个表格内的所有条目数量 假设有一个名为 employees 的员工息表,要查询这个表里有多少位雇员可以这样写 SQL 查询语句: ```sql SELECT COUNT(*) AS total_employees FROM employees; ``` 这条命令将会给出 employees 表里的全部记录数目,并把结果标记为 "total_employees"[^1]。 #### 示例二:依据某一条件筛选后的计数 继续沿用上述例子,如果我们只想知道部门编号(department_id)等于 20 的那些职员人数怎么办呢?这时就需要加入 WHERE 子句来进行过滤了: ```sql SELECT COUNT(*) AS dept_20_count FROM employees WHERE department_id = 20; ``` 此查询仅考虑那些 department_id 字段值为 20 的行并报告它们的数量。 #### 示例三:忽略重复项进行独立实体计数 有时候可能希望了解某类事物的不同实例个数而非简单累加每一笔资料。比如想知道公司内部存在多少种不同的职位(job_title),就可以采用 DISTINCT 关键字配合 COUNT 来达成目标: ```sql SELECT COUNT(DISTINCT job_title) AS unique_job_titles FROM employees; ``` 这段代码的作用在于先找出所有独一无二的 job_title 后再对其做总计操作。 ### 注意事项 - 如果表达式涉及多个列,则只要任意一列为NULL就不会纳入到最终的结果之中。 - 当运用 DISTINCT 参数的时候要注意性能开销可能会有所增加因为系统需要额外处理去重逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

收获不止数据库

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值