一、因前期TABLE的存储TABLESPACE设计不合理,或者须要对某个TABLESPACE进行维护管理,须要将该TABLESPACE中的对象转移, ORACLE提供了ALTER TABLE TABLE_NAME MOVE TABLESPACE NEW_TABLESPACE(须要有该表空间权限)的支持。sql
二、在MOVE TABLESPACE过程当中须要注意含LOB字段的表不能直接MOVE,以及分区表的MOVE,在MOVE TABLESPACE以后,对应表的 INDEX将会失效,须要重建。ide
三、为此写了一个PL/SQL程式进行批量MOVE(未通过严格的测试,请勿在生产库上使用,不然后果请自行承担) 测试
PL/SQL以下: spa
DECLARE v_sqltext1 VARCHAR2 (1000); v_sqltext2 VARCHAR2 (1000); v_sqltext3 VARCHAR2 (1000); v_sqltext4 VARCHAR2 (1000); v_sqltext5 VARCHAR2 (1000); v_sqltext6 VARCHAR2 (1000); v_sqltext7 VARCHAR2 (1000); CURSOR tabletype_cur IS SELECT * FROM dba_tables WHERE owner = 'SCOTT' AND tablespace_name = 'USERS'; v_table_str tabletype_cur%ROWTYPE; CURSOR lob_cur (lobtable VARCHAR2) IS SELECT * FROM dba_lobs WHERE table_name = lobtable; CURSOR index_cur (idx VARCHAR2) IS SELECT index_name FROM dba_indexes WHERE table_name = idx; CURSOR part_index_cur (partidx VARCHAR) IS SELECT index_name FROM dba_indexes WHERE table_name = partidx MINUS SELECT index_name FROM dba_part_indexes; BEGIN OPEN tabletype_cur; LOOP FETCH tabletype_cur INTO v_table_str; IF v_table_str.partitioned = 'NO' --是否为分区表 THEN FOR movelob IN lob_cur (v_table_str.table_name) --是否含有LOB字段 LOOP v_sqltext1 := 'ALTER TABLE SCOTT.' || movelob.table_name || ' MOVE LOB(' || movelob.column_name || ') STORE AS ' || movelob.segment_name || ' (TABLESPACE TEST)'; EXECUTE IMMEDIATE v_sqltext1; --DBMS_OUTPUT.put_line (v_sqltext1); END LOOP; v_sqltext2 := 'ALTER TABLE SCOTT.' || v_table_str.table_name || ' MOVE TABLESPACE TEST'; --DBMS_OUTPUT.put_line (v_sqltext2); EXECUTE IMMEDIATE v_sqltext2; --移动普通表 FOR moveidx IN index_cur (v_table_str.table_name) --将移动以后表的对应INDEX重建 LOOP v_sqltext3 := 'ALTER INDEX SCOTT.' || moveidx.index_name || ' REBUILD ONLINE TABLESPACE TEST'; EXECUTE IMMEDIATE v_sqltext3; --DBMS_OUTPUT.put_line (v_sqltext3); END LOOP; END IF; IF v_table_str.partitioned = 'YES' THEN --分区表分区的移动,暂不考虑有子分区的状况,若MOVE子分区将报ORA-14257 FOR part IN (SELECT partition_name FROM dba_tab_partitions WHERE subpartition_count = 0 AND table_name = v_table_str.table_name) LOOP v_sqltext4 := 'ALTER TABLE SCOTT.' || v_table_str.table_name || ' MOVE PARTITION ' || part.partition_name || 'TABLESPACE TEST'; EXECUTE IMMEDIATE v_sqltext4; --DBMS_OUTPUT.put_line (v_sqltext4); FOR movepartidx1 IN (SELECT index_name FROM dba_ind_partitions WHERE subpartition_count = 0 AND partition_name = part.partition_name) LOOP v_sqltext5 := 'ALTER INDEX ' || movepartidx1.index_name || ' REBUILD PARTITION ' || part.partition_name || ' TABLESPACE TEST'; EXECUTE IMMEDIATE v_sqltext5; --将移动以后分区表的分区INDEX重建 END LOOP; END LOOP; v_sqltext6 := 'ALTER TABLE SCOTT.' || v_table_str.table_name || 'MODIFY DEFAULT ATTRIBUTES TABLESPACE TEST'; EXECUTE IMMEDIATE v_sqltext6; --DBMS_OUTPUT.put_line (v_sqltext6); FOR movepartidx2 IN part_index_cur (v_table_str.table_name) --将移动以后分区表的全局INDEX重建 LOOP v_sqltext7 := 'ALTER INDEX SCOTT.' || movepartidx2.index_name || ' REBUILD ONLINE TABLESPACE TEST'; EXECUTE IMMEDIATE v_sqltext7; --DBMS_OUTPUT.put_line (v_sqltext7); END LOOP; END IF; END LOOP; CLOSE tabletype_cur; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.put_line (SQLERRM); END; /
总结:该PL/SQL主要是经过判断一个用户下的表是否为分区表进行move,并根据该表的对象类型来作处理,存在过多的逻辑判断,比较繁琐, 且是根据表类型来进行的,有比较大的局限性,后面考虑从须要move的tablespace方向出发,对tablespace上的对象分类进行move。如: A)先将该tablespace中的含LOB字段的表move,并重建索引。 B)以后将该tablespace中的分区表进行move,包含分区,子分区,并重建索引,包含全局索引,分区索引,含子分区索引。 C)在以后查看该tablespace中是否有LONG字段的表,有就进行处理。 D) 以后对剩下的普通表进行move,并重建索引,就可将整个tablespace中的对象move。 最后,对于move table的做用和影响请结合shrink table自行查询。设计