为提高效率,提问时请提供以下信息,问题描述清晰可优先响应。
【DM版本】: Dm8
【操作系统】:docker
【CPU】: docker
【问题描述】*:
有一张表,我要对它进行加密,原来的表大小占用115.5M,加密后的表大小占用540M,但是磁盘减少了4460M,感觉像是加密过程中修改表结构造成的,请问怎么占用这么大的磁盘空间?
在MySQL里面就没这么大,在MySQL中,表大小为130M,加密后是300M,但是磁盘减少了1005M,怎么两个数据库差距这么大,还是说两个数据库的机制不一样,请问差距在哪里?
你对表进行加密操作,是用类似下面这个ALTER语句实现的么?
ALTER TABLE 表名
MODIFY
(
列1 类型 ENCRYPT WITH 加密设置,
列2 类型 ENCRYPT WITH 加密设置,
列3 类型 ENCRYPT WITH 加密设置,
。。。
);
我刚刚测试了一下,这个 ALTER TABLE MODIFY 对字段进行更新时,会把完整的表数据在表空间里COPY一次。类似于先用MODIFY后的表结构CREATE个新表,然后把原表数据搬过去,再DROP掉原表这样的过程。
而如果更新多个字段,貌似是逐列循环处理的,每个字段都要搬一次。所以当MODIFY的字段比较多的话,就会造成占用大量的表空间,不知道为啥这样处理,搞不懂。
我测试过程大概如下:
刚MODIFY后,空闲表空间大小基本未变,但过一段时间后再查询能看到表空间被释放出来,估计是有后台刷新线程。
感觉比较郁闷的是释放出来的表空间无法通过ALTER TABLESPACE RESIZE DATAFILE的方式回收。
从V$DATAFILE表中 FREE_PAGE_NO 列内容看,估计MODIFY后的表中数据占用了靠后也就是新扩展的表数据文件中位置。所以无法收回这块磁盘空间了。
你可以测试一下,用下面这个SQL查一下作加密处理的表实际数据/索引等占用的表空间大小,以及这个表所使用的表空间名
WITH T_TAB AS
(
SELECT USR.NAME AS USER_NAME
,SCH.NAME AS SCHEMA_NAME
,TAB.NAME AS TABLE_NAME
,SUM(NVL(DECODE(BITAND(IDXINFO.XTYPE,0x01),0,ROUND(INDEX_USED_PAGES(IDX.ID) * PAGE / 1024.0 / 1024.0,2)),0)) ||'/'||
SUM(NVL(DECODE(BITAND(IDXINFO.XTYPE,0x01),0,ROUND(INDEX_USED_SPACE(IDX.ID) * PAGE / 1024.0 / 1024.0,2)),0)) AS CLUSTER_SIZE_MB
,SUM(NVL(DECODE(BITAND(IDXINFO.XTYPE,0x01),1,ROUND(INDEX_USED_PAGES(IDX.ID) * PAGE / 1024.0 / 1024.0,2)),0)) ||'/'||
SUM(NVL(DECODE(BITAND(IDXINFO.XTYPE,0x01),1,ROUND(INDEX_USED_SPACE(IDX.ID) * PAGE / 1024.0 / 1024.0,2)),0)) AS INDEX_SIZE_MB
,LISTAGG(DISTINCT TS.NAME,',') WITHIN GROUP (ORDER BY TS.ID) AS USED_TABLESPACE
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 SYSOBJECTS IDX ON IDX.SUBTYPE$ = 'INDEX' AND IDX.PID = TAB.ID
JOIN SYSINDEXES IDXINFO ON IDXINFO.ID = IDX.ID
JOIN V$TABLESPACE TS ON TS.ID = IDXINFO.GROUPID
GROUP BY USR.NAME,SCH.NAME,TAB.NAME
)
SELECT TAB.USER_NAME
,TAB.SCHEMA_NAME
,TAB.TABLE_NAME
,ROUND(TABLE_USED_PAGES(TAB.SCHEMA_NAME,TAB.TABLE_NAME) * PAGE / 1024.0 / 1024.0,2) ||'/'||
ROUND(TABLE_USED_SPACE(TAB.SCHEMA_NAME,TAB.TABLE_NAME) * PAGE / 1024.0 / 1024.0,2) AS TABLE_DATA_SIZE_MB
,ROUND(TABLE_USED_LOB_PAGES(TAB.SCHEMA_NAME,TAB.TABLE_NAME) * PAGE / 1024.0 / 1024.0,2) ||'/'||
ROUND(TABLE_USED_LOB_SPACE(TAB.SCHEMA_NAME,TAB.TABLE_NAME) * PAGE / 1024.0 / 1024.0,2) AS TABLE_LOB_SIZE_MB
,TAB.CLUSTER_SIZE_MB
,TAB.INDEX_SIZE_MB
,TAB.USED_TABLESPACE
FROM T_TAB TAB
WHERE TABLE_NAME = '表名'
然后再用下面这个SQL查一下表空间的使用情况。
最后的 DATAFILE_MINSIZE 列是根据FREE_PAGE_NO估算出的该数据文件回收后的最小尺寸。
SELECT TS.NAME AS TABLESPACE_NAME
,ROUND(TS.TOTAL_SIZE * PAGE / 1024.0 / 1024.0,2) AS TOTAL_MB
,ROUND(TS.USED_SIZE * PAGE / 1024.0 / 1024.0,2) AS USED_MB
,ROUND((TS.TOTAL_SIZE - TS.USED_SIZE) * PAGE / 1024.0 / 1024.0,2) AS FREE_MB
,DF.PATH AS DATAFILE_PATH
,ROUND(DF.TOTAL_SIZE * PAGE / 1024.0 / 1024.0,2) AS DATAFILE_TOTAL_MB
,ROUND((DF.TOTAL_SIZE - DF.FREE_SIZE) * PAGE / 1024.0 / 1024.0,2) AS DATAFILE_USED_MB
,ROUND(DF.FREE_SIZE * PAGE / 1024.0 / 1024.0,2) AS DATAFILE_FREE_MB
,ROUND(LEAST(DF.TOTAL_SIZE,GREATEST((DF.FREE_PAGE_NO - 1),4096)) * PAGE / 1024.0 / 1024.0,2)AS DATAFILE_MINSIZE
FROM V$TABLESPACE TS
,V$DATAFILE DF
WHERE DF.GROUP_ID = TS.ID
ORDER BY TS.ID,DF.ID
有大佬吗?