Одно из нововведений Oracle 10g это корзина. Эта возможность работает аналогично корзине в OC Windows или Mac OS. В этой статье будет описано, как работать с корзиной.
Начало
Существует два представления корзины: USER_RECYCLEBIN и DBA_RECYCLEBIN. Для удобства синоним RECYCLEBIN указывает на ваш USER_RECYCLEBIN. По умолчанию корзина активирована, но ее можно отключить в инициализационном параметре RECYCLEBIN, на уровне сессии или системы.
Когда корзина активна, любые таблицы, которые вы удаляете, не удаляются полностью, а попадают в корзину. Вместо того что бы удалить таблицу, Oracle переименовывает ее и все связанные объекты (индексы, триггеры, LOB сегменты и т.д.). Дает им системное имя, которое начинается на BIN$.
Например, рассмотрим такую ситуацию:
SQL> CREATE TABLE TEST (COL VARCHAR2(10), CHANGE_DATE DATE);
TABLE created.
SQL> INSERT INTO TEST VALUES ('Версия 1', SYSDATE);
1 row created.
SQL> SELECT * FROM TEST ;
COL CHANGE_DATE
Версия 1 14:10:03
Если параметр RECYCLEBIN выставлен в значением ON, (по-умолчанию в Oracle 10g он включен), удаление таблицы приведет к ее перемещению в корзину.
SQL>DROP TABLE TEST;
TABLE dropped.
SQL> SELECT OBJECT_NAME, ORIGINAL_NAME, TYPE,
2 CAN_UNDROP AS "UND", CAN_PURGE AS "PUR", DROPTIME
3 FROM RECYCLEBIN;
SQL>
OBJECT_NAME ORIGINAL_NAME TYPE UND PUR DROPTIME
BIN$HGnc55/7rRPgQPeM/qQoRw==$0 TEST TABLE YES YES 2008-09-24:15:45:22
Таким образом видим, что таблица переименована, все данные которые в ней содержались, по прежнему находятся в ней. Для Oracle это по прежнему, обычная таблица.
SQL> ALTER SESSION SET NLS_DATE_FORMAT='HH24:MI:SS';
Session altered.
SQL> SELECT * FROM "BIN$HGnc55/7rRPgQPeM/qQoRw==$0";
COL CHANGE_DATE
Версия 1 14:10:03
Поскольку данные все на месте, то не составит труда вернуть из корзины таблицу обратно. Эта операция известна как «flashback drop». Команда FLASHBACK TABLE... TO BEFORE DROP переименовывает таблицу из имени с BIN$ в ее оригинальное имя, в нашем случае TEST.
SQL> FLASHBACK TABLE TEST TO BEFORE DROP;
Flashback complete.
SQL> SELECT * FROM TEST;
COL CHANGE_DATE
Версия 1 14:10:03
SQL> SELECT * FROM RECYCLEBIN;
no rows selected
Следует помнить, что после удаления таблицы она только переименовывается, но не удаляется физически. Сегменты таблицы, по прежнему, находятся в табличном пространстве, и занимают место. Вы можете удалить объект из корзины восстановив его или удалив из корзины.
SQL>DROP TABLE TEST;
TABLE dropped.
SQL> SELECT OBJECT_NAME, ORIGINAL_NAME, TYPE,
2 CAN_UNDROP AS "UND", CAN_PURGE AS "PUR", DROPTIME
3 FROM RECYCLEBIN;
SQL>
OBJECT_NAME ORIGINAL_NAME TYPE UND PUR DROPTIME
BIN$HGnc55/7rRPgQPeM/qQoRw==$0 TEST TABLE YES YES 2008-09-24:16:05:54
SQL> PURGE TABLE "BIN$HGnc55/7rRPgQPeM/qQoRw==$0";
TABLE purged.
SQL> SELECT * FROM RECYCLEBIN;
no rows selected
Есть несколько опций удаления. Можно удалить все из USER_RECYCLEBIN используя PURGE RECYCLEBIN; пользователь с привилегиями DBA может удалить все из всех корзин, используя DBA_RECYCLEBIN; и наконец, можно очистить корзину по схеме и пользователю, используя PURGE TABLESPACE USER.
Oracle сохраняет объекты в таблице до тех пор пока вы не удалили их, или в табличном пространстве хватает места, или не превышена квота пользователя. Очистка произойдет одной операцией с текущего момента до тех пор, пока не освободится достаточно места для текущей операции. Если файлы данных табличного пространства с опцией AUTOEXTEND ON, корзина будет очищена до того как сработает автоприращение.
Удаление версий таблицы
Точно так же как в корзине Windows может быть несколько файлов с одинаковым именем и расширением, в корзине Oracle может быть несколько версий таблицы. Создадим и удалим дважды таблицу TEST.
SQL> CREATE TABLE TEST (COL VARCHAR2(10), CHANGE_DATE DATE);
TABLE created.
SQL> INSERT INTO TEST VALUES ('Версия 1', SYSDATE);
1 row created.
SQL>DROP TABLE TEST;
TABLE dropped.
SQL> CREATE TABLE TEST (COL VARCHAR2(10), CHANGE_DATE DATE);
TABLE created.
SQL> INSERT INTO TEST VALUES ('Версия 2', SYSDATE);
1 row created.
SQL>DROP TABLE TEST;
TABLE dropped.
SQL> SELECT OBJECT_NAME, ORIGINAL_NAME, TYPE,
2 AN_UNDROP AS "UND", CAN_PURGE AS "PUR", DROPTIME
3 FROM RECYCLEBIN;
SQL>
OBJECT_NAME ORIGINAL_NAME TYPE UND PUR DROPTIME
BIN$HGnc55/7rRPgQPeM/qQoRw==$0 TEST TABLE YES YES 2008-09-24:16:05:54
BIN$HGnc55/8rRPgQPeM/qQoRw==$0 TEST TABLE YES YES 2008-09-24:16:10:54
Сделаем запрос к таблицам, что бы убедится, что они разные:
SQL> SELECT * FROM "BIN$HGnc55/7rRPgQPeM/qQoRw==$0";
COL CHANGE_DATE
Версия 1 14:10:03
SQL> SELECT * FROM "BIN$HGnc55/8rRPgQPeM/qQoRw==$0";
COL CHANGE_DATE
Версия 2 15:38:03
Теперь возникает вопрос, какую версию Oracle восстановит при указании FLASHBACK DROP?
SQL> FLASHBACK TABLE TEST TO BEFORE DROP;
Flashback complete.
SQL> SELECT * FROM TEST;
COL CHANGE_DATE
Версия 2 15:38:03
Oracle всегда восстанавливает последнюю по времени версию объекта. Чтобы восстановить более раннюю версию можно указать имя таблицы для восстановления. Сейчас в корзине две версии:
SQL> SELECT OBJECT_NAME, ORIGINAL_NAME, TYPE,
2 CAN_UNDROP AS "UND", CAN_PURGE AS "PUR", DROPTIME
3 FROM RECYCLEBIN;
SQL>
OBJECT_NAME ORIGINAL_NAME TYPE UND PUR DROPTIME
BIN$HGnc55/7rRPgQPeM/qQoRw==$0 TEST TABLE YES YES 2008-09-24:16:05:54
BIN$HGnc55/8rRPgQPeM/qQoRw==$0 TEST TABLE YES YES 2008-09-24:16:10:54
Для восстановления первой версии будем использовать имя первого экземляра:
SQL> FLASHBACK TABLE BIN$HGnc55/7rRPgQPeM/qQoRw==$0 TO BEFORE DROP;
Flashback complete.
SQL> SELECT * FROM TEST;
COL CHANGE_DATE
Версия 1 14:10:03
Вторая версия осталась в корзине:
SQL> SELECT OBJECT_NAME, ORIGINAL_NAME, TYPE,
2 CAN_UNDROP AS "UND", CAN_PURGE AS "PUR", DROPTIME
3 FROM RECYCLEBIN;
SQL>
OBJECT_NAME ORIGINAL_NAME TYPE UND PUR DROPTIME
BIN$HGnc55/8rRPgQPeM/qQoRw==$0 TEST TABLE YES YES 2008-09-24:16:10:54
Зависимые объекты
В современных базах данных очень редки ситуации, когда таблица существует сама по себе. Как правило, они имеют индексы, триггеры, связи ограничения. Удаление таблицы приводит к удалению всех зависимых объектов. При удалении все объекты, как и таблица, переименовываются, их новое имя начинается так же с BIN$.
SQL> TRANCATE TABLE TEST;
TABLE truncated.
SQL> INSERT INTO TEST VALUES ('Версия 3', SYSDATE);
1 row created.
SQL> CREATE INDEX TEST_COL_IDX ON TEST(COL);
Index created.
SQL> SELECT * FROM TEST;
COL CHANGE_DATE
Версия 3 16:59:21
SQL>DROP TABLE TEST;
TABLE dropped.
SQL> SELECT OBJECT_NAME, ORIGINAL_NAME, TYPE,
2 CAN_UNDROP AS "UND", CAN_PURGE AS "PUR", DROPTIME
3 FROM RECYCLEBIN ORDER BY DROPTIME;
SQL>
OBJECT_NAME ORIGINAL_NAME TYPE UND PUR DROPTIME
BIN$HGnc55/8rRPg TEST TABLE YES YES 2008-09-24:16:10:54
QPeM/qQoRw==$0
BIN$HGnc55//rRPg TEST TABLE YES YES 2006-09-01:17:08:41
QPeM/qQoRw==$0
BIN$HGnc55/+rRPg TEST_COL_IDX INDEX NO YES 2006-09-01:17:08:41
QPeM/qQoRw==$0
Представление RECYCLEBIN имеет и другие столбцы, показывающие и связь между TEST и TEST_COL_IDX.
SQL> ALTER SESSION SET NLS_DATE_FORMAT='HH24:MI:SS';
SQL> SELECT OBJECT_NAME, ORIGINAL_NAME, TYPE,
2 CAN_UNDROP AS "UND", CAN_PURGE AS "PUR", DROPTIME,
3 BASE_OBJECT, PURGE_OBJECT
4 FROM RECYCLEBIN
5 ORDER BY DROPTIME;
SQL>
OBJECT_NAME ORIGINAL_NAME TYPE UND PUR DROPTIME BASE_OBJECT PURGE_OBJECT
BIN$HGnc55/8rRPg TEST TABLE YES YES 16:10:54 233032 233032
QPeM/qQoRw==$0
BIN$HGnc55//rRPg TEST TABLE YES YES 17:08:41 233031 233031
QPeM/qQoRw==$0
BIN$HGnc55/+rRPg TEST_COL_IDX INDEX NO YES 17:08:41 233031 233434
QPeM/qQoRw==$0
Колонка PURGE_OBJECT содержит номер самого объекта, BASE_OBJECT содержит номер главного объекта. Таблица TEST имеет номер 233031, базовый объект для нее – тот же самый, т.е. она сама себе базовый объект. Индекс TEST_COL_IDX имеет номер 233434, а базовый объект для него – 233031, таблица TEST.
Если выполнить FLASHBACK TABLE для таблицы TEST, ее индекс будет восстановлен, но Oracle не переименует его обратно в оригинальное имя. У индекса так и останется имя BIB$.
SQL> FLASHBACK TABLE TEST TO BEFORE DROP;
Flashback complete.
SQL> SELECT * FROM TEST;
COL CHANGE_DATE
Версия 3 16:59:21
SQL> SELECT * INDEX_NAME FROM USER_INDEXES WHERE TABLE_NAME='TEST';
INDEX_NAME
BIN$HGnc55/+rRPgQPeM/qQoRw==$0
Скорее всего, Oracle не особо заботится о сохранении оригинального имени индекса. Если сейчас снова удалить копию таблицы TEST, то выяснится, что Oracle «не помнит» оригинального имени индекса.
SQL>DROP TABLE TEST;
TABLE dropped.
SQL> SELECT OBJECT_NAME, ORIGINAL_NAME, TYPE,
2 CAN_UNDROP AS "UND", CAN_PURGE AS "PUR",
3 DROPTIME, BASE_OBJECT, PURGE_OBJECT
4 FROM RECYCLEBIN
5 ORDER BY DROPTIME;
SQL>
OBJECT_NAME ORIGINAL_NAME TYPE UND PUR DROPTIME BASE_OBJECT PURGE_OBJECT
BIN$HGnc55/8rRPg TEST TABLE YES YES 16:10:54 233032 233032
QPeM/qQoRw==$0
BIN$HGnc55//rRPg TEST TABLE YES YES 17:08:41 233031 233031
QPeM/qQoRw==$0
BIN$HGnc56AArRPg BIN$HGnc55/+rRP INDEX NO YES 17:08:41 233031 233434
QPeM/qQoRw==$1
gQPeM/qQoRw==$0
Обратите внимание на значения в столбцах CAN_UNDROP и CAN_PURGE (мы их показываем как UND и PUR) для индекса. Индекс не может быть восстановлен без таблицы, значение CAN_UNDROP равно NO. В то же время индекс может быть удален без таблицы.
SQL> PURGE INDEX "BIN$HGnc56AArRPgQPeM/qQoRw==$1";
Index purged.
SQL> SELECT OBJECT_NAME, ORIGINAL_NAME, TYPE,
2 CAN_UNDROP AS "UND", CAN_PURGE AS "PUR",
3 DROPTIME, BASE_OBJECT, PURGE_OBJECT
4 FROM RECYCLEBIN
5 ORDER BY DROPTIME;
SQL>
OBJECT_NAME ORIGINAL_NAME TYPE UND PUR DROPTIME BASE_OBJECT PURGE_OBJECT
BIN$HGnc55/8rRPg TEST TABLE YES YES 16:10:54 233032 233032
QPeM/qQoRw==$0
BIN$HGnc55//rRPg TEST TABLE YES YES 17:08:41 233031 233031
QPeM/qQoRw==$0
Сейчас если восстановить таблицу, то она будет восстановлена без индекса
SQL> FLASHBACK TABLE TEST TO BEFORE DROP;
Flashback complete.
SQL> SELECT * FROM TEST;
COL CHANGE_DATE
Версия 3 16:59:21
SQL> SELECT * INDEX_NAME FROM USER_INDEXES WHERE TABLE_NAME='TEST';
no rows selected
Если удалите таблицу со связанными LOB сегментами, то с ними будет подобная ситуация, исключение состоит в том, что они не могут быть независимо удалены, CAN_UNDROP и CAN_PURGE будут выставлены в NO. Если восстановить таблицу то они будут восстановлены вместе с ней, если таблица будет удалена из корзины, то и они будут удалены.
Ограничения
- Если удаляется таблица и затем восстанавливается, ссылочная целостность теряется.
- Для материализованных представлений, если удаляется таблица, все журналы определенные для этой таблицы удаляются без помещения в корзину.
- Если удаляется базовая таблица, то bitmap индексы не помещаются в корзину. При восстановлении таблицы из корзины индексы не восстанавливаются.
Отключение корзины
Аналогично корзине в Windows, где можно удалить файл, минуя корзину, в Oracle реализован такой же механизм. Для этого в предложении DROP TABLE указывается PURGE.
SQL> PURGE RECYCLEBIN;
Recyclebin purged.
SQL> SELECT * FROM RECYCLEBIN;
no rows selected
SQL> CREATE TABLE NEW_TABLE (COL1 VARCHAR2(10), COL2 VARCHAR2(10));
TABLE created.
SQL> DROP TABLE NEW_TABLE PURGE;
TABLE dropped.
SQL> SELECT * FROM RECYCLEBIN;
no rows selected
Если отключать корзину на уровне сессии, то требуется выполнить предложение ALTER SESSION SET RECYCLEBIN=OFF. Это даст тот же эффект, что и добавление PURGE в предложение DROP TABLE. Но, стоит отметить, что можно использовать FLASHBACK DROP для восстановления объектов, которые были помещены в корзину до того как было выполнено отключение корзины.
SQL> SELECT OBJECT_NAME, ORIGINAL_NAME, TYPE,
2 CAN_UNDROP AS "UND", CAN_PURGE AS "PUR",
3 DROPTIME, BASE_OBJECT, PURGE_OBJECT
4 FROM RECYCLEBIN
5 ORDER BY DROPTIME;
SQL>
OBJECT_NAME ORIGINAL_NAME TYPE UND PUR DROPTIME BASE_OBJECT PURGE_OBJECT
BIN$HGnc56ACrRPg TEST TABLE YES YES 16:10:54 233032 233032
QPeM/qQoRw==$0
SQL> ALTER SESSION SET RECYCLEBIN=OFF;
Session altered.
SQL> CREATE TABLE TEST (COL VARCHAR2(10), CHANGE_DATE DATE);
TABLE created.
SQL> INSERT INTO TEST VALUES ('Версия 5', SYSDATE);
1 row created.
SQL> DROP TABLE TEST;
TABLE dropped.
SQL> SELECT OBJECT_NAME, ORIGINAL_NAME, TYPE,
2 CAN_UNDROP AS "UND", CAN_PURGE AS "PUR",
3 DROPTIME, BASE_OBJECT, PURGE_OBJECT
4 FROM RECYCLEBIN
5 ORDER BY DROPTIME;
SQL>
OBJECT_NAME ORIGINAL_NAME TYPE UND PUR DROPTIME BASE_OBJECT PURGE_OBJECT
BIN$HGnc56ACrRPg TEST TABLE YES YES 16:10:54 233032 233032
QPeM/qQoRw==$0
SQL> FLASHBACK TABLE TEST TO BEFORE DROP;
Flashback complete.
SQL> SELECT * FROM TEST;
COL CHANGE_DATE
Версия 3 16:59:21
Выводы
- Корзина может содержать несколько версий одного объекта.
- Oracle восстанавливает объекты по алгоритму LIFO, можно восстановить старейшую версию, с указанием прямого имени объекта.
- Oracle при удалении основного объекта удаляет и зависимые объекты, при восстановлении зависимые объекты восстанавливаются (за исключением ограничений указанных выше). Для индексов при восстановлении не восстанавливается оригинальное имя.
- При отключении корзины, возможность восстановить объекты из нее остается, это касается объектов помещенных в корзину до ее отключения.