Фрагментация таблиц в Oracle - dbms_redefinition

ОГЛАВЛЕНИЕ

Опция: 4 "dbms_redefinition"

SQL> CREATE TABLE TABLE1 (
2 NO NUMBER,
3 NAME VARCHAR2(20) DEFAULT 'NONE',
4 DDATE DATE DEFAULT SYSDATE);
TABLE created.

SQL> ALTER TABLE TABLE1 ADD CONSTRAINT PK_NO PRIMARY KEY(NO);
TABLE altered.

SQL> BEGIN
2 FOR X IN 1..100000 LOOP
3 INSERT INTO TABLE1 ( NO , NAME, DDATE)
4 VALUES ( X , DEFAULT, DEFAULT);
5 END LOOP;
6 END;
PL/SQL procedure successfully completed.

SQL> CREATE OR REPLACE TRIGGER TRI_TABLE1
2 AFTER INSERT ON TABLE1
3 BEGIN
4 NULL;
5 END;
Trigger created.

SQL> SELECT COUNT(*) FROM TABLE1;
COUNT(*)
----------
100000

SQL> DELETE TABLE1 WHERE ROWNUM <= 50000;
50000 rows deleted.

SQL> COMMIT;
Commit complete.

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS('SCOTT','TABLE1');
PL/SQL procedure successfully completed.

SQL> SELECT TABLE_NAME, ROUND((BLOCKS*8),2)//'KB' "SIZE"
2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'TABLE1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
TABLE1 2960KB

SQL> SELECT TABLE_NAME, ROUND((NUM_ROWS*AVG_ROW_LEN/1024),2)//'KB' "SIZE"
2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'TABLE1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
TABLE1 822.69KB

SQL> --Требуется роль "DBA" или "SELECT" на dbms_redefinition pkg
SQL> --Проверьте что таблица кандидат на переопределение.
SQL>
SQL> EXEC SYS.DBMS_REDEFINITION.CAN_REDEF_TABLE
2 ('SCOTT',-> 'TABLE1',-> 
3 SYS.DBMS_REDEFINITION.CONS_USE_PK);
PL/SQL procedure successfully completed.

SQL> -- После проверки таблицы на возможность переопределения, вручную 
SQL> -- создается пустая временная таблица (в той же схеме и точно такая же 
SQL> -- как переопределяемая)
SQL>
SQL> CREATE TABLE TABLE2 AS SELECT * FROM TABLE1 WHERE 1 = 2;
TABLE created.

SQL> EXEC SYS.DBMS_REDEFINITION.START_REDEF_TABLE
2 ( 'SCOTT',-> 'TABLE1',-> 'TABLE2');
PL/SQL procedure successfully completed.

SQL> --Эта процедура синхронизирует две таблицы, исходную и временную.
SQL>
SQL> EXEC SYS.DBMS_REDEFINITION.SYNC_INTERIM_TABLE
2 ('SCOTT',-> 'TABLE1',-> 'TABLE2');
PL/SQL procedure successfully completed.

SQL> --Создаем PRIMARY KEY на временную таблицу(TABLE2)
SQL> ALTER TABLE TABLE2
2 ADD CONSTRAINT PK_NO1 PRIMARY KEY (NO);
TABLE altered.

SQL> CREATE TRIGGER TRI_TABLE2
2 AFTER INSERT ON TABLE2
3 BEGIN
4 NULL;
5 END;
Trigger created.

SQL> -- Отключаем внешний ключ на оригинальной таблице, 
SQL> -- если существует, прежде чем завершить процесс.
SQL>
SQL> EXEC SYS.DBMS_REDEFINITION.FINISH_REDEF_TABLE
2 ( 'SCOTT',-> 'TABLE1',-> 'TABLE2');
PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS('SCOTT','TABLE1');
PL/SQL procedure successfully completed.

SQL> SELECT TABLE_NAME, ROUND((BLOCKS*8),2)//'KB' "SIZE"
2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'TABLE1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
TABLE1 1376KB

SQL> SELECT TABLE_NAME, ROUND((NUM_ROWS*AVG_ROW_LEN/1024),2)//'KB' "SIZE"
2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'TABLE1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
TABLE1 841.4KB

SQL> SELECT STATUS,CONSTRAINT_NAME
2 FROM USER_CONSTRAINTS
3 WHERE TABLE_NAME = 'TABLE1';
STATUS CONSTRAINT_NAME
-------- ------------------------------
ENABLED PK_NO1

SQL> SELECT STATUS ,TRIGGER_NAME
2 FROM USER_TRIGGERS
3 WHERE TABLE_NAME = 'TABLE1';
STATUS TRIGGER_NAME
-------- ------------------------------
ENABLED TRI_TABLE2

SQL> DROP TABLE TABLE2 PURGE;
TABLE dropped. 
Какой из способов подходит вам, смотрите по ситуации.