Oracle impdp只导入元数据占用大量空间以及如何删除空段

 

Oracle impdp只导入元数据占用大量空间以及如何删除空段

 

从某个库导出整个库的元数据,在另外一个新库导入元数据,发现导入时间久并且占用了大量空间。

有好几张的空表甚至能占用十几二十G大小的空间,看了一下都是按天分区的间隔分区表,每个分区会有8M的大小。

 

通过在源库使用dbms_metadata.get_ddl包查看某张表的ddl(不要用PLSQL Developer工具看)可以发现原因,

1、表的ddl中带了子句“SEGMENT CREATION IMMEDIATE”,即会立刻分配一个段给到表(或者分区)

2、表的ddl中分区表的每个分区的storage的初始化大小initial为8388608,即8k

导致在新库导入元数据的时候,也会分配空间,并且是每个分区都是8k。

 

那么现在又有另外的两个问题:

1、数据库参数deferred_segment_creation为默认值true,表示创建空表的时候不会分配空间,为什么ddl中会带“SEGMENT CREATION IMMEDIATE”

2、默认的ASSM管理表空间中,默认情况下,普通表的段里边的区大小是0~15号都是64k大小,而分区表是否每个分区则是8M。

 

先解答这两个疑问,

第一个问题很好解答,只要表里边曾经存在过数据,那么ddl的属性会自动变成“SEGMENT CREATION IMMEDIATE”,无论deferred_segment_creation是不是true

测试如下(需要使用非SYS用户):

16:27:59 SYS@xxxxdb(79)> show parameter deferred_segment_creation

NAME                                 TYPE                              VALUE
------------------------------------ --------------------------------- ------------
deferred_segment_creation            boolean                           TRUE
16:28:02 SYS@xxxxdb(79)> conn zkm/zkm
Connected.
16:28:50 ZKM@xxxxdb(79)> create table test(id int,name varchar2(20));

Table created.

Elapsed: 00:00:00.02


16:29:07 SYS@szceb2(81)> select dbms_metadata.get_ddl('TABLE','TEST','ZKM') from dual;

DBMS_METADATA.GET_DDL('TABLE','TEST','ZKM')
--------------------------------------------------------------------------------

  CREATE TABLE "ZKM"."TEST"
   (    "ID" NUMBER(*,0),
        "NAME" VARCHAR2(20)
   ) SEGMENT CREATION DEFERRED
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
 NOCOMPRESS LOGGING
  TABLESPACE "USERS"


16:29:46 ZKM@xxxxdb(79)> insert into test values(1,'zkm');

1 row created.

Elapsed: 00:00:00.01

16:29:08 SYS@szceb2(81)> select dbms_metadata.get_ddl('TABLE','TEST','ZKM') from dual;

DBMS_METADATA.GET_DDL('TABLE','TEST','ZKM')
--------------------------------------------------------------------------------

  CREATE TABLE "ZKM"."TEST"
   (    "ID" NUMBER(*,0),
        "NAME" VARCHAR2(20)
   ) SEGMENT CREATION IMMEDIATE
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
 NOCOMPRESS LOGGING
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXT
ENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS"

 

 

第二个问题测试,

16:49:22 ZKM@xxxxdb(79)> CREATE TABLE test
16:49:35   2   (    "USERNAME" VARCHAR2(30) NOT NULL ENABLE,
16:49:35   3        "USER_ID" NUMBER NOT NULL ENABLE,
16:49:35   4        "ACCOUNT_STATUS" VARCHAR2(32) NOT NULL ENABLE,
16:49:35   5        "LOCK_DATE" DATE,
16:49:35   6        "EXPIRY_DATE" DATE,
16:49:35   7        "DEFAULT_TABLESPACE" VARCHAR2(30) NOT NULL ENABLE,
16:49:35   8        "TEMPORARY_TABLESPACE" VARCHAR2(30) NOT NULL ENABLE,
16:49:35   9        "CREATED" DATE NOT NULL ENABLE,
16:49:35  10        "INITIAL_RSRC_CONSUMER_GROUP" VARCHAR2(30),
16:49:35  11        "EXTERNAL_NAME" VARCHAR2(4000),
16:49:35  12        "CREATE_TIME" DATE
16:49:35  13   )
16:49:35  14  PARTITION BY RANGE ("CREATE_TIME") INTERVAL(NUMTODSINTERVAL(1,'DAY'))
16:49:36  15   (PARTITION "P_INIT"  VALUES LESS THAN (TO_DATE('2024-07-08 00:00:00', 'YYYY-MM-DD HH24:MI:SS')));

Table created.

Elapsed: 00:00:00.04
16:49:37 ZKM@xxxxdb(79)> select extent_id,blocks,sys.format_bytes(bytes) sizes from user_extents where segment_name='TEST' order by extent_id;

no rows selected

Elapsed: 00:00:00.02
16:49:44 ZKM@xxxxdb(79)> INSERT INTO TEST SELECT T.*,SYSDATE FROM USER_USERS T WHERE ROWNUM=1;

1 row created.

Elapsed: 00:00:00.06
16:50:00 ZKM@xxxxdb(79)> select extent_id,blocks,sys.format_bytes(bytes) sizes from user_extents where segment_name='TEST' order by extent_id;

 EXTENT_ID     BLOCKS   SIZES
---------- ---------- ----------
         0       1024      8 MiB

Elapsed: 00:00:00.04

 

那么,impdp如何导入元数据的时候不要常见段呢?可以使用transform=segment_attributes:N,忽略“SEGMENT CREATION IMMEDIATE”,

eg:

impdp \' / as sysdba \' directory=dir20240704 dumpfile=metadata_DB.dmp logfile=imp_metadata_DB.log cluster=n schemas=user1,user2,user3 exclude=statistics,db_link table_exists_action=skip content=metadata_only transform=segment_attributes:N

 

对于已经分配了空间的空闲段,可以使用如下脚本来进行回收空间,

BEGIN
DBMS_SPACE_ADMIN.drop_empty_segments (
schema_name => 'schema',
table_name => 'table_name',
partition_name => 'partition_name');
END;
/

 

如果上边的参数为null,表示通配符,所有的空段都会被删除,比如直接执行下边的语句,会删除整个库里边的空段。

https://www.cnblogs.com/PiscesCanon/p/18290344

BEGIN
DBMS_SPACE_ADMIN.drop_empty_segments (
schema_name => '',
table_name => '',
partition_name => '');
END;
/

 

也可以只指定schema_name为某个用户,即删除某个用户下的所有空段。

 

posted @ 2024-07-08 17:03  PiscesCanon  阅读(79)  评论(0编辑  收藏  举报