有大字段,初始化表空间才128M
为提高效率,提问时请提供以下信息,问题描述清晰可优先响应。
【DM版本】: --03134283890-20220720-165295-10045 Pack11
【操作系统】:CentOS Linux 7
【CPU】:8C 16G
【问题描述】*:字符集 UTF-8,页大小32K
表空间自增异常,创建表空间默认扩展大小时是4M,但是使用过程中表空间增长异常大,期间没有大量删除操作,导致空间使用率极低,占用大量磁盘空间
试过逻辑备份还原和DTS迁移,导入新表空间也有同样的问题。
表空间创建的时候,初始化大小设置的是多少?
逻辑还原和DTS这种,涉及到了表数据的增长,这些表里边是否有大字段
有大字段,初始化表空间才128M
下面内容只是我个人的理解,不知道是否属实,你可以测试验证下。
查一下下面这个SQL,看看目前在 129 这个表空间里有多少个索引。
SELECT COUNT(1),SF_GET_EXTENT_SIZE,PAGE
FROM SYSINDEXES
WHERE GROUPID = 129
复制
达梦在创建一张表或一个索引时,会初始分配至少1个簇的空间,比如1个簇是16页,每页32K,这样等于初始一张表或创建一个索引就会至少占用16*32=512K的大小。
现在你设置的数据文件每次扩展4M,也就是4096K,折算下来只相当于8个簇的大小。
如果创建了比较多的表或索引,那初始占用的空间就已经很大了。
当某个表中的数据占满了之前分配的簇空间后,再分配空间也是1个簇,也就是又分配16个32K页。
算下来占用和空闲空间差的还是很大
1簇32页,1页32K,也就是说,1个簇会占用32*32=1024K,也就是1M。
现在索引(含聚簇索引)总数是3521,也就是创建了这些对象最小也要占用3521M.
从前面你查的V$DATAFILE信息看,目前该数据文件大小(TOTAL_SIZE)是186880页,算下来是5840M.
你可以用下面这个SQL查一下每个表的大小,看下是哪些表占用了较多的空间(每个值都拆成字节大小和页数)。
SELECT USR.NAME AS USER_NAME
,SCH.NAME AS SCHEMA_NAME
,TAB.NAME AS TABLE_NAME
,IDX.TSID
,IDX.TSNAME AS TABLESPACE_NAME
,ROUND(TABLE_USED_PAGES(SCH.NAME,TAB.NAME) * PAGE ,2) AS TABLE_SIZE_BYTES
,TABLE_USED_PAGES(SCH.NAME,TAB.NAME) AS TABLE_SIZE_PAGES
,ROUND(TABLE_USED_SPACE(SCH.NAME,TAB.NAME) * PAGE ,2) AS TABLE_SPACE_BYTES
,TABLE_USED_SPACE(SCH.NAME,TAB.NAME) AS TABLE_SPACE_PAGES
,CASE WHEN HAS_CLUSTER = 1 THEN ROUND(TABLE_USED_LOB_PAGES(SCH.NAME,TAB.NAME) * PAGE ,2) END AS TABLE_LOB_SIZE_BYTES
,CASE WHEN HAS_CLUSTER = 1 THEN TABLE_USED_LOB_PAGES(SCH.NAME,TAB.NAME) END AS TABLE_LOB_SIZE_PAGES
,CASE WHEN HAS_CLUSTER = 1 THEN ROUND(TABLE_USED_LOB_SPACE(SCH.NAME,TAB.NAME) * PAGE ,2) END AS TABLE_LOB_SPACE_BYTES
,CASE WHEN HAS_CLUSTER = 1 THEN TABLE_USED_LOB_SPACE(SCH.NAME,TAB.NAME) END AS TABLE_LOB_SPACE_PAGES
,IDX.CLUSTER_SIZE_BYTES
,IDX.CLUSTER_SIZE_PAGES
,IDX.CLUSTER_SPACE_BYTES
,IDX.CLUSTER_SPACE_PAGES
,IDX.INDEX_SIZE_BYTES
,IDX.INDEX_SIZE_PAGES
,IDX.INDEX_SPACE_BYTES
,IDX.INDEX_SPACE_PAGES
,COMM.COMMENT$
FROM SYSOBJECTS TAB
JOIN SYSOBJECTS SCH ON SCH.TYPE$ = 'SCH' AND SCH.ID = TAB.SCHID
JOIN SYSOBJECTS USR ON USR.TYPE$ = 'UR' AND USR.ID = SCH.PID
JOIN (SELECT IDX.PID AS TABLE_ID
,TS.ID AS TSID
,MAX(TS.NAME) AS TSNAME
,MAX(DECODE(BITAND(IDXINFO.XTYPE,0x01),0,1,0)) AS HAS_CLUSTER
,SUM(NVL(DECODE(BITAND(IDXINFO.XTYPE,0x01),0,ROUND(INDEX_USED_PAGES(IDX.ID) * PAGE ,2)),0)) AS CLUSTER_SIZE_BYTES
,SUM(NVL(DECODE(BITAND(IDXINFO.XTYPE,0x01),0,INDEX_USED_PAGES(IDX.ID)),0)) AS CLUSTER_SIZE_PAGES
,SUM(NVL(DECODE(BITAND(IDXINFO.XTYPE,0x01),0,ROUND(INDEX_USED_SPACE(IDX.ID) * PAGE ,2)),0)) AS CLUSTER_SPACE_BYTES
,SUM(NVL(DECODE(BITAND(IDXINFO.XTYPE,0x01),0,INDEX_USED_SPACE(IDX.ID)),0)) AS CLUSTER_SPACE_PAGES
,SUM(NVL(DECODE(BITAND(IDXINFO.XTYPE,0x01),1,ROUND(INDEX_USED_PAGES(IDX.ID) * PAGE ,2)),0)) AS INDEX_SIZE_BYTES
,SUM(NVL(DECODE(BITAND(IDXINFO.XTYPE,0x01),1,INDEX_USED_PAGES(IDX.ID)),0)) AS INDEX_SIZE_PAGES
,SUM(NVL(DECODE(BITAND(IDXINFO.XTYPE,0x01),1,ROUND(INDEX_USED_SPACE(IDX.ID) * PAGE ,2)),0)) AS INDEX_SPACE_BYTES
,SUM(NVL(DECODE(BITAND(IDXINFO.XTYPE,0x01),1,INDEX_USED_SPACE(IDX.ID)),0)) AS INDEX_SPACE_PAGES
FROM SYSOBJECTS IDX
JOIN SYSINDEXES IDXINFO ON IDXINFO.ID = IDX.ID
JOIN V$TABLESPACE TS ON TS.ID = IDXINFO.GROUPID
WHERE IDX.TYPE$ = 'TABOBJ'
AND IDX.SUBTYPE$ = 'INDEX'
GROUP BY IDX.PID,TS.ID
) IDX ON IDX.TABLE_ID = TAB.ID
LEFT JOIN SYSTABLECOMMENTS COMM ON COMM.TABLE_TYPE = 'TABLE' AND COMM.SCHNAME = SCH.NAME AND COMM.TVNAME = TAB.NAME
WHERE TAB.TYPE$ = 'SCHOBJ'
AND TAB.SUBTYPE$ IN ('STAB','UTAB')
AND IDX.TSID = 129
ORDER BY TABLE_SPACE_PAGES DESC
复制
你说的空闲空间是指 V$DATAFILE里的FREE_SIZE吧?
这个FREE_SIZE是指空闲页数量。
比如说,创建一张空表后会初始分配1个簇的空间,共32页。
而实际只使用了2页,剩余30页都是FREE状态。
但这30页的空间并不是真正可以释放掉的,因为在分配簇时已经确认了簇相关的页号范围。
目前 TOTAL_SIZE是 186880,FREE_SIZE 是169754,差值是 17126页,平均到每个索引上是约5页左右。
去掉每个对象都会有的1个控制页,也就是平均下来每个索引使用了4个页(全满或半满状态的)。
按32K每页,不考虑页头占用大小,把树内节点页也算作数据页,每页都按全满(FULL)状态来计算,
就是每张表数据占用144KB,我觉得这个大小还好吧。
理解了,开始主要是对空闲空间疑惑,因为达梦是参考了Oracle的架构,oracle里空闲表空间是可以使用的。达梦对于表空间使用分配是不是有些不合理,初始化就需要3.5G,空闲页不能回收,也不能再分配使用,oracle中这些表初始化只需要200M。对于测试创建大量数据库磁盘使用不太友好
抱歉,我刚刚才想明白,我前面对 V$DATAFILE 中 TOTAL_SIZE 和 FREE_SIZE 的描述是错误的。
TOTAL_SIZE 应该是指对这个表空间的数据文件分配的磁盘占用空间大小,并不是我前面描述的页面占用空间。
FREE_SIZE 则应该是指这个数据文件内未被分配的空间大小。
这样的话就存在些解释不清楚的地方了
前面查询索引数是 3521,按每个索引只创建一个簇,那初始化后占用页面数是 3521 * 32 = 112672页,应该剩余未分配页面数最大是 186880 - 112672 = 74208页
而目前从 V$DATAFILE 查询数据看,FREE_SIZE 是 169754 页。
可能我的理解还是有问题,有点晕。。。
你得空时可以做一个实验。
首先查询一下 V$DATAFILE 中 FREE_SIZE 值。
然后随便创建一张表,结构很简单就可以,比如说
CREATE TABLE T_PGTST(A INT);
然后再查一下V$DATAFILE 看 FREE_SIZE变化多少。
如果FREE_SIZE减少了32,那就说明每创建一个表或索引会初始化一个簇页空间,并从可用空间里扣减1个簇的页数。
如果改变值小于32,比如只变小了2,则说明在你使用的DM版本中,这里记录的FREE_SIZE只计算了实际占用的页数,而不是按簇分配页数计算的。
我刚刚在我手头两个不同版本的库(210820 和 250117)分别测试了一下,两个库的簇大小都是16页
在250117版本中,新增一张表后,FREE_SIZE减少16,也就是减小一个簇的页数
在210820版本中,新增一张表后,FREE_SIZE减少2,也就是只计算了1个内节点页和1个控制页,其他簇页没有计算。
我看你这里版本是220720,估计也是类似的情况。
现在的问题就是,对于早期版本,这些空闲状态簇页是否可以被其他索引重用或被收回?
如果不能收回,则说明虽然FREE_SIZE只扣减了2个已使用页,但实际表空间里还是已经预分配了1个簇的页数,只是未使用页是不可收回或重用状态。
这样的话,你新增对象后表空间大小增长速度比较快就能解释了。
测试了两个版本20220720和20230417,测试结果和你的一致,说明早期版本和高版本free_size意义就不一样。空闲簇页都不能被回收利用,导致数据文件占磁盘空间过快
我觉得你目前的问题还是簇页数和页面大小太大了。
可以测试下,单独建一个新实例,设置一簇16页,每页8K或16K大小。
然后初始化表和索引对象。再看下数据文件大小增长情况。
使用视图SYS.V$LONG_EXEC_SQLS 查询慢sql时,拿到的sql信息是不完整的,中间使用...省略号替代了
发布于 2025/04/15
系统保留字
发布于 2025/04/15
.net执行Insert报不完整的语法项
发布于 2025/04/15
go-20240918这个驱动能用在20240527的版本上吗
发布于 2025/04/15
.netCore3.1连接数据库报错
发布于 2025/04/15
使用视图SYS.V$LONG_EXEC_SQLS 查询慢sql时,拿到的sql信息是不完整的,中间使用...省略号替代了
发布于 2025/04/15
系统保留字
发布于 2025/04/15
.net执行Insert报不完整的语法项
发布于 2025/04/15
go-20240918这个驱动能用在20240527的版本上吗
发布于 2025/04/15
.netCore3.1连接数据库报错
发布于 2025/04/15
初始128M