Oracle-在线迁移表到新表空间

前言:

​在Oracle线上系统中,我们经常会需要迁移表到新表空间或者通过move tablespace的方式去清理高水位等类似迁移场景,但通过move操作会导致锁表的发生,这在线上系统是不可接受的,在Oracle11g提供了在线重定义的方式,通过dbms_redefinition进行在线表迁移,避免了长时间锁表的发生、影响业务的连续性。

在线迁移场景:

测试通过在线重定义将表t1从表空间users迁移到newtbs。

在线迁移步骤:

Oracle-在线迁移表到新表空间_第1张图片

在线迁移实施步骤:

1 检查一下t1表能否进行重定义,如果执行成功,则表示可以,否则将会报错显示错误原因

注意:在线重定义需要表有主键,没有主键无法执行在线重定义,会报ORA-12089: cannot online redefine table ""."" with no primary key

exec dbms_redefinition.can_redef_table('TEST','T1');
---成功执行代表符合
PL/SQL procedure successfully completed.

2 获取原始表的ddl

---获取原始表的ddl语句,索引,约束,权限
set pagesize 5000
set long 50000
set longc 50000
select dbms_metadata.get_ddl('TABLE','T1','TEST')   from dual
union all
select dbms_metadata.get_dependent_ddl('CONSTRAINT','T1','TEST')  from dual
union all
select dbms_metadata.get_dependent_ddl('INDEX','T1','TEST')   from dual
union all
select dbms_metadata.get_dependent_ddl('OBJECT_GRANT','T1','TEST')  from dual;
---执行结果
  CREATE TABLE "TEST"."T1"
   (    "ID" NUMBER(10,0),
        "CREATE_DATE" DATE,
        "NAME" VARCHAR2(100),
        "NAM1" CLOB,
         PRIMARY KEY ("ID")
  USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS"  ENABLE
   ) SEGMENT CREATION IMMEDIATE
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
 NOCOMPRESS LOGGING
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS"
 LOB ("NAM1") STORE AS SECUREFILE (
  TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192
  NOCACHE LOGGING  NOCOMPRESS  KEEP_DUPLICATES
  STORAGE(INITIAL 106496 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT));
​
  ALTER TABLE "TEST"."T1" ADD PRIMARY KEY ("ID")
  USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS"  ENABLE;
​
  CREATE UNIQUE INDEX "TEST"."SYS_C007597" ON "TEST"."T1" ("ID")
  PCTFREE 10 INITRANS 2 MAXTRANS 255
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS"
  CREATE UNIQUE INDEX "TEST"."SYS_IL0000074011C00004$$" ON "TEST"."T1" (
  PCTFREE 10 INITRANS 2 MAXTRANS 255
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS"
  PARALLEL (DEGREE 0 INSTANCES 0)
  CREATE INDEX "TEST"."IND_T1" ON "TEST"."T1" ("CREATE_DATE")
  PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS";
​
  GRANT SELECT ON "TEST"."T1" TO "TEST_1";

3 将获取语句中的表名t1,替换为T1_NEW,表空间users,替换为newtbs

---主键约束可以不用手动添加,因为创建表语句里面已经包含
---对于SYS_IL..$$的lob字段索引也可以不用手动添加,因为创建表语句里面已经包含
---对于索引,如果表数据太大,可以选择全量数据同步之后再创建索引
​
  CREATE TABLE "TEST"."T1_NEW"
   (    "ID" NUMBER(10,0),
        "CREATE_DATE" DATE,
        "NAME" VARCHAR2(100),
        "NAM1" CLOB,
         PRIMARY KEY ("ID")
  USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "NEWTBS"  ENABLE
   ) SEGMENT CREATION IMMEDIATE
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
 NOCOMPRESS LOGGING
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "NEWTBS"
 LOB ("NAM1") STORE AS SECUREFILE (
  TABLESPACE "NEWTBS" ENABLE STORAGE IN ROW CHUNK 8192
  NOCACHE LOGGING  NOCOMPRESS  KEEP_DUPLICATES
  STORAGE(INITIAL 106496 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT));
​
  
  CREATE INDEX "TEST"."IND_T1_NEW" ON "TEST"."T1_NEW" ("CREATE_DATE")
  PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "NEWTBS";
​
  GRANT SELECT ON "TEST"."T1_NEW" TO "TEST_1";

4 开始全量数据初始化,此操作期间对于要迁移的数据,如果存在行上锁还未释放,操作会产生产生等待TX 6锁

SQL> BEGIN
DBMS_REDEFINITION.start_redef_table(
uname => 'TEST', 
orig_table => 'T1',
int_table => 'T1_NEW');
END;
/

5 手动触发增量数据到新表,避免增量数据差异过大,即使finish_redef_table也会再一次同步数据(可选)

SQL> BEGIN
dbms_redefinition.sync_interim_table(
uname => 'TEST', 
orig_table => 'T1',
int_table => 'T1_NEW');
END;
/

6 查看重定义的状态

---可以通过以下视图查看在线重定义表的状态
select * from DBA_REDEFINITION_ERRORS;
select * from DBA_REDEFINITION_OBJECTS;
select * from DBA_REDEFINITION_STATUS;
主要关注当前的操作,以及操作状态,如果当前没有正在进行的redefiniton操作,则视图都为空

7 进行表切换,此操作期间需要短暂获取TM 6锁(正常应用无感知),以完成表切换

SQL> BEGIN
dbms_redefinition.finish_redef_table(
uname => 'TEST',
orig_table => 'T1',
int_table => 'T1_NEW');
END;
/

8 确认T1是否已经迁移到新的表空间newtbs

select owner,table_name,tablespace_name
from dba_tables
where owner='TEST' and table_name='T1';
​
select owner,index_name,tablespace_name
from dba_indexes
where owner='TEST' and table_name='T1';
​
select segment_name,table_name,tablespace_name
from dba_lobs
where owner='TEST' and table_name='T1';
​
 select grantee,owner,table_name
 from dba_tab_privs
 where table_name='T1';
​
OWNER     TABLE_NAME                TABLESPACE_NAME
---------- ------------------------------ ------------------------------------------------------------
TEST     T1                        NEWTBS
​
OWNER     INDEX_NAME                  TABLESPACE_NAME
---------- ----------------------------------- ------------------------------------------------------------
TEST     SYS_IL0000074174C00004$$             NEWTBS
TEST     SYS_C007598                   NEWTBS
TEST     IND_T1_NEW                   NEWTBS
​
​
SEGMENT_NAME               TABLE_NAME                         TABLESPACE_NAME
------------------------------ ------------ ------------------------------------------------------------
SYS_LOB0000074174C00004$$         T1                            NEWTBS
​
GRANTEE            OWNER    TABLE_NAME
---------------- ---------- ----------------------------------------
TEST_1             TEST            T1

9 查看表依赖对象是否无效

---如果无效需要手动重新编译
select a.owner,a.name,a.type,a.REFERENCED_OWNER,a.REFERENCED_NAME,b.status  from dba_DEPENDENCIES a,dba_objects b 
where a.REFERENCED_OWNER='TEST' and a.REFERENCED_NAME='T1' and a.NAME=b.object_name;
​
OWNER     NAME       TYPE           REFERENCED_OWNER    REFERENCED STATUS
---------- ---------- ------------------------------ -------------------- ---------- --------------
TEST     P1_T1      PROCEDURE          TEST      T1       VALID

10 执行统计信息

exec DBMS_STATS.GATHER_TABLE_STATS(ownname=>'TEST',tabname=>'T1',ESTIMATE_PERCENT=>20,method_opt=>'for all columns size 1',cascade=>true,force=>true,degree=>2,no_invalidate=>FALSE); 

11 验证数据

SQL> select count(*) from test.t1 where id < 3002822;
​
  COUNT(*)
----------
    302821
​
SQL> select count(*) from test.t1_new where id < 3002822;
​
  COUNT(*)
----------
    302821

你可能感兴趣的:(Oracle,oracle,dba,数据库,迁移学习,sql)