在数据库数据导出过程中,发现名称格式为 CMP3xxx 的表(如 CMP396874),这类表并非业务表,而是 Oracle 压缩顾问运行时生成的临时中间表,以下是完整的解析与操作指南。
SQL> select t.last_analyzed, t.owner, t.table_namefrom dba_tables t where t.table_namelike'CMP%';
LAST_ANALYZED OWNER TABLE_NAME
------------------- ------------------------------ ------------------------------
2024-06-0206:00:13 RM CMP3$96874
2024-01-1922:12:54 RM CMP3$93830
2021-05-2222:05:50 RM CMP3$93816
2024-07-1922:00:16 RM CMP3$90752
2024-05-2606:00:19 RM CMP3$90456
2024-01-1922:12:54 RM CMP3$90377
2024-01-1922:12:54 RM CMP3$90370
2024-01-1922:12:54 RM CMP3$111853
2024-01-1922:12:54 RM CMP3$111839
9 rows selected.
SQL> 注:SELECT 语句可正常查询表内数据,但其数据为源表副本,无独立业务价值。
CMP3$96874 是 Oracle 数据库中 DBMS_COMPRESSION(压缩顾问)的临时产物,命名规则拆解:
CMP3$xxx 是 Oracle 压缩顾问执行 GET_COMPRESSION_RATIO 或 ADVISE_COMPRESSION 存储过程时的中间产物,核心用于在不影响生产数据的前提下,计算表的压缩比、测试压缩算法效果。
CMP3$xxx 是 Oracle 压缩顾问(DBMS_COMPRESSION)执行 GET_COMPRESSION_RATIO 或 ADVISE_COMPRESSION 存储过程时的中间产物:
keep_temp_tables => TRUE(默认 FALSE),也会主动保留这些表用于后续分析。压缩顾问通过多阶段生成临时表完成压缩测试,各阶段表的作用与数据特征如下:
表名 | 数据量特征 | 核心作用 | 存储空间占比 |
|---|---|---|---|
CMP1$xxx | 源表10%采样 | 快速预计算压缩比(轻量测试) | 约源表10% |
CMP2$xxx | 采样数据 | 适配压缩算法的格式转换 | 与CMP1$xxx接近 |
CMP3$xxx | 源表全量 | 全量数据压缩测试(核心表) | 与源表基本一致 |
CMP4$xxx | 压缩后全量 | 存储压缩结果,计算最终比值 | 取决于压缩比(更低) |
正常情况下,压缩顾问生成报告后会自动清理所有 CMP$ 系列临时表,残留仅见于以下场景:
keep_temp_tables => TRUE(默认值为 FALSE),主动保留临时表用于后续分析;CMP3$xxx 为源表全量副本,若源表为TB级,会直接占用等量存储空间;dba_tables/dba_objects)的查询负担,降低元数据操作效率;CMP$ 系列表均为临时测试表,无业务逻辑依赖,删除后不影响源表及业务功能。CMP3$xxx 表的结构与源表完全一致(字段名、数据类型、约束、索引等);sample_percent 参数,也可能为采样子集;-- 方式1:对比表行数/存储空间,匹配源表候选(RM用户为例)
SELECT t.table_name, t.num_rows, t.blocks, t.bytes/1024/1024 AS size_mb
FROM dba_tables t
WHERE t.owner = 'RM'
AND t.num_rows > 0
AND t.table_nameNOTLIKE'CMP%' -- 排除临时表,筛选源表
ORDERBY t.bytesDESC;
-- 方式2:查询表的创建审计日志(需开启数据库审计功能)
SELECT owner, obj_name, action_name, timestamp, os_username
FROM dba_audit_object
WHERE obj_name = 'CMP3$96874'
AND action_name = 'CREATE TABLE';
-- 方式3:对比表结构,精准匹配源表
SELECT a.table_nameAS 源表名
FROM (
-- 提取非CMP表的结构特征
SELECT table_name,
LISTAGG(column_name||' '||data_type, ',') WITHIN GROUP (ORDERBY column_id) AS struct_hash
FROM dba_tab_columns
WHERE owner = 'RM'AND table_name NOTLIKE'CMP%'
GROUPBY table_name
) a
JOIN (
-- 提取CMP3$96874的结构特征
SELECT LISTAGG(column_name||' '||data_type, ',') WITHIN GROUP (ORDERBY column_id) AS struct_hash
FROM dba_tab_columns
WHERE owner = 'RM'AND table_name = 'CMP3$96874'
GROUPBY table_name
) b ON a.struct_hash = b.struct_hash;执行以下SQL可全量查询数据库中所有压缩顾问临时表:
SELECT owner,
table_name,
tablespace_name,
num_rows,
bytes/1024/1024 AS size_mb, -- 表占用空间(MB)
last_analyzed -- 最后分析时间
FROM dba_tables
WHERE table_name REGEXP_LIKE('^CMP[1-4]?\$\d+$', 'i') -- 匹配CMP$xxx/CMP1$xxx等格式
ORDERBY owner, size_mb DESC;CMP$ 系列表无业务数据,可直接删除,建议添加 PURGE 关键字跳过回收站,避免二次占用空间:
-- 以SYS或RM用户执行,替换为实际表名
DROPTABLE"RM"."CMP3$96874" PURGE;先生成删除脚本,验证无误后执行,避免误删:
-- 步骤1:生成批量删除脚本
SELECT'DROP TABLE "'||owner||'"."'||table_name||'" PURGE;'AS delete_sql
FROM dba_tables
WHERE owner = 'RM' -- 限定目标用户,缩小范围
AND table_name REGEXP_LIKE('^CMP[1-4]?\$\d+$', 'i');
-- 步骤2:执行生成的脚本(示例)
DROPTABLE"RM"."CMP3$96874" PURGE;
DROPTABLE"RM"."CMP3$93830" PURGE;
DROPTABLE"RM"."CMP3$93816" PURGE;
-- 其他表删除语句...调用 DBMS_COMPRESSION 时,强制设置 keep_temp_tables => FALSE(双重保障,默认值已为FALSE):
DECLARE
v_comp_ratio NUMBER; -- 压缩比
v_blk_comp NUMBER; -- 压缩后块数
v_blk_uncomp NUMBER; -- 压缩前块数
BEGIN
DBMS_COMPRESSION.GET_COMPRESSION_RATIO(
scratchtbsname => 'USERS', -- 临时表空间
ownname => 'RM', -- 源表所属用户
tabname => 'SOURCE_TABLE', -- 待测试的源表名
partname => NULL, -- 分区名(无分区则填NULL)
comptype => DBMS_COMPRESSION.COMP_FOR_OLTP, -- 压缩类型(OLTP压缩)
keep_temp_tables => FALSE, -- 关键:执行后自动删除临时表
compression_ratio => v_comp_ratio,
compressed_blocks => v_blk_comp,
uncompressed_blocks => v_blk_uncomp
);
DBMS_OUTPUT.PUT_LINE('压缩比:'||ROUND(v_comp_ratio, 2));
END;
/创建定时任务,每日清理残留的 CMP$ 表,避免堆积:
BEGIN
-- 创建定时任务
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'RM_CLEAN_CMP_TEMP_TABLES', -- 任务名
job_type => 'PLSQL_BLOCK', -- 任务类型
job_action => '
DECLARE
CURSOR c_cmp_tables IS
SELECT ''DROP TABLE "''||owner||''"."''||table_name||''" PURGE;'' AS sql_stmt
FROM dba_tables
WHERE owner = ''RM''
AND table_name REGEXP_LIKE(''^CMP[1-4]?\$\d+$'', ''i'');
BEGIN
FOR rec IN c_cmp_tables LOOP
EXECUTE IMMEDIATE rec.sql_stmt;
END LOOP;
END;',
start_date => SYSTIMESTAMP, -- 立即生效
repeat_interval => 'FREQ=DAILY;BYHOUR=23;BYMINUTE=0', -- 每日23点执行
enabled => TRUE, -- 启用任务
comments => '每日清理RM用户的压缩顾问临时表'
);
END;
/