达梦管理堆表,全部参照官方文档。
- 普通表都是以B树形式存放的,ROWID都是逻辑的ROWID,即从1一直增长下去。在并发情况下,每次插入过程都需要逻辑生成ROWID,这样影响了插入数据的效率;对于每一条数据都需要存储ROWID值,也会花费较大的存储空间。堆表就是基于上述两个理由而提出的,堆表是指采用了物理ROWID形式的表,即使用文件号、页号和页内偏移而得到ROWID值,这样就不需要存储ROWID值,可以节省空间。逻辑ROWID在插入或修改过程中,为了确保ROWID的唯一性,需要依次累加而得到值,这样就影响了效率,而堆表只需要根据自己的文件号、页号和页内偏移就可以得到ROWID,提高了效率。
- 采用了物理ROWID形式的堆表,DM服务器内部对聚集索引进行了调整,没有采用传统的B树结构,取而代之的是“扁平B树”,数据页都是通过链表形式存储。为支持并发插入,扁平B树可以支持最多128个数据页链表(最多64个并发分支和最多64个非并发分支),在B树的控制页中记录了所有链表的首、尾页地址。对于非并发分支,若分支数有多个,即存在多个链表,则不同的用户登陆系统后,会根据其事务ID号,随机选择一条链表来对堆表进行插入操作;对于并发分支,则不同用户会选择不同的分支来进行插入,若存在多个用户选择了同一条分支的情况,才需要等待其他用户插入结束并释放锁之后才能进行插入。在并发情况下,不同用户可以在不同的链表上进行插入,效率得到较大提升。(这一段没看明白,听这个意思我感觉并发分支和非并发分支都能并发操作啊,难道非并发分支一旦被某个用户选定了就不能再被其它用户选定?)
- 堆表的创建方式有两种:一种是设置ini参数LIST_TABLE(取值为1时,若建表时未指定表是否为堆表或非堆表时,默认为堆表;取值为0时,若建表时未指定表是否为堆表或非堆表时,默认为普通形式。取值默认为0);一种是建表时显式指定,不管参数LIST_TABLE设置为何值,创建表时可以在STORAGE选项中指定需要创建的表形式。
- 与堆表创建形式相关的关键字有三个,分别是NOBRANCH、BRANCH、CLUSTERBTR。NOBRANCH:若指定为NOBRANCH,则创建的表为堆表,并发分支个数为0,非并发分支个数为1。如:CREATE TABLE TEST(A INT,B VARCHAR)STORAGE(NOBRANCH);;BRANCH(N,M):若为该形式,则创建的表为堆表,并发分支个数为n,非并发分支个数为m。如:CREATE TABLE TEST(A INT,B VARCHAR)STORAGE(BRANCH(2,2));;BRANCH N:指定创建的表为堆表,并发分支个数为n,非并发分支个数为0;CLUSTERBTR:创建的表为非堆表,即普通B树表。如:CREATE TABLE TEST(A INT,B VARCHAR)STORAGE(CLUSTERBTR);。
- 堆表的限制:聚集索引和列存储。堆表采用了物理ROWID,即通过文件号、页号和页内偏移直接生成该值,这样若知道了ROWID值,也就知道文件号、页号和页内偏移这些变量,就可以直接定位到某条记录,所以没有必要再为堆表创建聚集索引了。在创建堆表时,系统会默认创建聚集索引,该索引只是一个根页信息,显式建立聚集索引是不允许的,若用户需要借助聚集索引主键对数据进行排序则不推荐使用堆表;由于列存储采用了不同方式对表进行物理存储,DM服务器暂不支持堆表的列存储。
- 堆表在进行数据扫描过程中,有着其先天的优势,若知道了数据记录的ROWID,则直接可以对ROWID进行解码,得到该纪录的文件号、页号和页内偏移,也就得到了该记录,所以建议在经常查询的列上建立二级索引,这样在进行操作中,先通过二级索引找到该记录ROWID,就可以直接找到数据,效率有较大提高。(那普通表,聚集主键不是ROWID时,建立二级索引,指向的是什么呢?ROWID还是聚集索引键?)
- 堆表虽然支持表的ALTER操作,但是建议轻易不要进行此类操作。对表进行ALTER操作,,数据记录的ROWID有可能发生改变,这样每次进行ALTER操作,都可能进行索引的重建,需要花费较多的时间。
- DM支持对堆表的备份与还原操作,还原数据时,B树数据和二级索引可以同时被还原。
- 可以通过系统过程SP_TABLEDEF(‘SCH_NAME’,’TAB_NAME’);查看堆表的定义,还可以使用SELECT TABLEDEF(‘SCH_NAME’,’TAB_NAME’);命令和SELECT DBMS_MEATDATA.GET_DDL(‘TABLE’,’TAB_NAME’,’SCH_NAME’);命令获取。