Как стать автором
Обновить

Ссылочное партиционирование в Oracle и опция flashback table to before drop

Ссылочное партиционирование позволяет организовать прозрачную для разработчика и пользователя поддержку партиционирования таблиц, связанных отношением master-child через внешние ключи.
Эта крайне удобная опция таит в себе однако одну скрытую особенность (не хочу говорить о баге в данном случае), которая может привести к случайной потере данных. В большей степени это касается экземпляров баз данных, на которых ведется разработка (и где высока вероятность, что кто-то выполнит 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 в этом случае не предусмотрел никакого механизма, который мог бы предупредить об опасности.
Будьте внимательны.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.