Ссылочное партиционирование позволяет организовать прозрачную для разработчика и пользователя поддержку партиционирования таблиц, связанных отношением master-child через внешние ключи.
Эта крайне удобная опция таит в себе однако одну скрытую особенность (не хочу говорить о баге в данном случае), которая может привести к случайной потере данных. В большей степени это касается экземпляров баз данных, на которых ведется разработка (и где высока вероятность, что кто-то выполнит DROP TABLE). Тем не менее, тот же казус может произойти и на продуктовых серверах в результате ошибок DBA.
Создадим пару таблиц, из которых одна — родительская, а вторая — дочерняя (имеется внешний ключ, ссылающийся на родительскую таблицу). Кроме того, сделаем таблицы партиционированными и обеспечим автоматическую поддержку партиций в дочерней таблице с помощью referential partitioning:
Допустим, что в результате ошибки (или преднамеренно) некто удалил дочернюю таблицу:
Казалось бы, ничего страшного — включенная опция recyclebin обеспечит нам восстановление таблицы (мы ведь пока ничего другого не делали), но не тут-то было:
Recyclebin включен — в этом можно убедиться:
На самом деле объяснение этому феномену очень простое — опция flashback table to before drop не восстанавливает внешние ключи (это отражено в документации). Поэтому Oracle просто не в состоянии восстановить дочернюю таблицу, поскольку механизм ссылочного партиционирования не может работать в отсутствие внешних ключей. К сожалению Oracle в этом случае не предусмотрел никакого механизма, который мог бы предупредить об опасности.
Будьте внимательны.
Эта крайне удобная опция таит в себе однако одну скрытую особенность (не хочу говорить о баге в данном случае), которая может привести к случайной потере данных. В большей степени это касается экземпляров баз данных, на которых ведется разработка (и где высока вероятность, что кто-то выполнит DROP TABLE). Тем не менее, тот же казус может произойти и на продуктовых серверах в результате ошибок DBA.
Создадим пару таблиц, из которых одна — родительская, а вторая — дочерняя (имеется внешний ключ, ссылающийся на родительскую таблицу). Кроме того, сделаем таблицы партиционированными и обеспечим автоматическую поддержку партиций в дочерней таблице с помощью referential partitioning:
SQL> CREATE TABLE PARENT_TAB (
2 PARENT_ID NUMBER NOT NULL,
3 PARENT_NAME VARCHAR2 (30) NOT NULL,
4 LOCAL_TRANSACTION_TIME TIMESTAMP NOT NULL,
5 CONSTRAINT PK_PARENT PRIMARY KEY (PARENT_ID))
6 PARTITION BY RANGE (LOCAL_TRANSACTION_TIME) (
7 PARTITION P_20090206 VALUES LESS THAN (TIMESTAMP' 2009-02-07 00:00:00'),
8 PARTITION P_20090207 VALUES LESS THAN (TIMESTAMP' 2009-02-08 00:00:00'),
9 PARTITION P_20090209 VALUES LESS THAN (TIMESTAMP' 2009-02-09 00:00:00'))
10 ENABLE ROW MOVEMENT;
Table created.
SQL> CREATE TABLE CHILD_TAB
2 (
3 CHILD_ID NUMBER,
4 PID NUMBER NOT NULL,
5 CLASSIFICATION NUMBER,
6 CONSTRAINT PK_CHILD PRIMARY KEY (CHILD_ID),
7 CONSTRAINT FK_CHILD_TO_PARENT FOREIGN KEY (PID) REFERENCES PARENT_TAB (PARENT_ID)
8 )
9 PARTITION BY REFERENCE (FK_CHILD_TO_PARENT)
10 ENABLE ROW MOVEMENT;
Table created.
SQL> INSERT INTO PARENT_TAB
2 VALUES(1,'PARENT X', TIMESTAMP' 2009-02-08 00:00:00')
3 /
1 row created.
SQL> INSERT INTO CHILD_TAB
2 VALUES(1,1,0)
3 /
1 row created.
SQL> commit;
Commit complete.
SQL> SELECT partition_name FROM user_tab_partitions
2 WHERE table_name = 'CHILD_TAB'
3 /
PARTITION_NAME
------------------------------
P_20090206
P_20090207
P_20090209
Допустим, что в результате ошибки (или преднамеренно) некто удалил дочернюю таблицу:
SQL> drop table child_tab;
Table dropped.
Казалось бы, ничего страшного — включенная опция recyclebin обеспечит нам восстановление таблицы (мы ведь пока ничего другого не делали), но не тут-то было:
SQL> flashback table child_tab to before drop;
flashback table child_tab to before drop
*
ERROR at line 1:
ORA-38305: object not in RECYCLE BIN
Recyclebin включен — в этом можно убедиться:
SQL> create table t (x int);
Table created.
SQL> drop table t;
Table dropped.
SQL> flashback table t to before drop;
Flashback complete.
На самом деле объяснение этому феномену очень простое — опция flashback table to before drop не восстанавливает внешние ключи (это отражено в документации). Поэтому Oracle просто не в состоянии восстановить дочернюю таблицу, поскольку механизм ссылочного партиционирования не может работать в отсутствие внешних ключей. К сожалению Oracle в этом случае не предусмотрел никакого механизма, который мог бы предупредить об опасности.
Будьте внимательны.