达梦数据库默认创建的是索引组织表,而Oracle数据库默认创建的是堆表。这两种表类型的区别主要体现在数据存储和组织方式上:
- 索引组织表(Index Organized Table, IOT):
索引组织表有且仅有一个聚簇索引键。索引组织表也称“普通表”,数据都是以B树形式存放的,ROWID都是逻辑的ROWID,即从1一直增长下去。在并发情况下,每次插入过程中都需要逻辑生成ROWID,这样影响了插入数据的效率;对于每一条数据都需要存储ROWID值,也会花费较大的存储空间。
索引组织表数据按照聚簇索引键排序(数据是有序的,插入有序)。 - 堆表(Heap Table):
堆表的数据是以挂链形式存储的,一般情况下,支持最多128个链表,一个链表在物理上就是一个段,堆表采用的是物理rowid,在插入过程中,rowid在事先已确定,并保证其唯一性,所以可以并发插入,插入效率很高,且由于rowid是即时生成,无需保存在物理磁盘上,也节省了空间。
堆表的数据存储没有特定的顺序,是随机存储的。
为支持并发插入,扁平B树可以支持最多128个数据页链表(最多64个并发分支和最多64个非并发分支),在B树的控制页中记录了所有链表的首、尾页地址。
NOBRANCH:如果指定为 NOBRANCH,则创建的表为堆表,并发分支个数为0,非并发分支个数为1;
BRANCH(N,M):如果为该形式,则创建的表为堆表,并发分支个数为N,非并发个数为M;
BRANCH N:指定创建的表为堆表,并发分支个数为 N,非并发分支个数为1;
CLUSTERBTR:创建的表为非堆表,即普通B树表。
用户可以在配置文件中,添加LIST_TABLE参数:
- 如果LIST_TABLE = 1,则在未显式指定表是否为堆表或非堆表时,默认情况下创建的表为堆表;
- 如果LIST_TABLE = 0,则在未显式指定表是否为堆表或非堆表时,默认情况下创建的表为普通表形式。
1. 创建表
创建索引组织表
CREATE TABLE CLUSTER_T1(C1 INT,C2 INT,C3 VARCHAR(20) ,C4 VARCHAR(20));
创建堆表
CREATE TABLE HEAP_T1(C1 INT ,C2 INT,C3 VARCHAR(20) ,C4 VARCHAR(20)) STORAGE(NOBRANCH);
通过DBA_TABLES视图区分索引组织表和堆表
SELECT TABLE_NAME, IOT_TYPE
FROM DBA_TABLES
WHERE TABLE_NAME IN ('CLUSTER_T1',
'HEAP_T1');
通过索引类型区分索引组织表和堆表,可以看到这两种类型的表都会创建一个默认索引
SELECT D1.TABLE_NAME,
D1.INDEX_NAME,
D1.INDEX_TYPE,
S2.XTYPE
FROM SYS.DBA_INDEXES D1
LEFT JOIN SYS.SYSOBJECTS S1
ON D1.INDEX_NAME=S1.NAME
AND S1.SCHID=(SELECT A.ID FROM SYSOBJECTS A WHERE A.TYPE$ ='SCH' AND A.NAME='SYSDBA')
LEFT JOIN SYS.SYSINDEXES S2
ON S1.ID=S2.ID
WHERE D1.TABLE_NAME IN ('CLUSTER_T1',
'HEAP_T1');
索引组织表只能创建一个聚集索引。手动再添加聚集索引,则会覆盖默认创建的聚集索引。
两张表添加主键索引,均为二级索引。
create cluster index "SYSDBA"."IDXC_CLUSTER_T1_C1" on "SYSDBA"."CLUSTER_T1"("C1");
alter table "SYSDBA"."CLUSTER_T1" add primary key("C1");
alter table "SYSDBA"."HEAP_T1" add primary key("C1");
2. 测试
插入数据
[执行语句1]:
TRUNCATE TABLE CLUSTER_T1;
执行成功, 执行耗时80毫秒. 执行号:33240
影响了0条记录
[执行语句2]:
TRUNCATE TABLE HEAP_T1;
执行成功, 执行耗时21毫秒. 执行号:33241
影响了0条记录
[执行语句3]:
INSERT INTO cluster_t1 SELECT LEVEL C1,level%100 C2,'test','test' FROM DUAL CONNECT BY LEVEL<=5000000;
执行成功, 执行耗时1分 28秒 933毫秒. 执行号:33242
影响了5,000,000条记录
[执行语句4]:
INSERT INTO HEAP_T1 SELECT LEVEL C1,level%100 C2,'test','test' FROM DUAL CONNECT BY LEVEL<=5000000;
执行成功, 执行耗时28秒 235毫秒. 执行号:33243
影响了5,000,000条记录
创建的HEAP_T2表,有并发分支2个,非并发分支4个
[执行语句1]:
CREATE TABLE HEAP_T2(C1 INT ,C2 INT,C3 VARCHAR(20) ,C4 VARCHAR(20)) STORAGE(BRANCH(2,4));
执行成功, 执行耗时8毫秒. 执行号:33247
影响了0条记录
[执行语句2]:
INSERT INTO HEAP_T2 SELECT LEVEL C1,level%100 C2,'test','test' FROM DUAL CONNECT BY LEVEL<=5000000;
执行成功, 执行耗时9秒 170毫秒. 执行号:33248
影响了5,000,000条记录
对比数据占用空间
select SEGMENT_NAME,BYTES/1024/1024 as SIZE_M from SYS.DBA_SEGMENTS where SEGMENT_NAME in ('CLUSTER_T1', 'HEAP_T1', 'HEAP_T2');
3. 总结
- 对于大数据量的存量数据表,使用索引组织表,占用空间更小;
- 对于经常有大批量的数据插入场景,使用堆表,插入速度更快,效率更高;
- 对于小数据量的表,使用索引组织表,虽然占用空间更多但可以接受;
- 堆表增加并发分支和非并发分支,效率会更高。
达梦社区地址
https://eco.dameng.com