СУБД
Добавил(а) shixaro, последний раз редактировал(а) shixaro Mar 26, 2015  (посмотреть изменения)
Метки: 

Oracle позволяет выполнять ретроспективные запросы - в разрезе времени - которые могут оказаться очень полезными. Особенно в случае если данные были удалены - случайно или намеренно - и их надо восстановить.

Допустим, когда-то создавалась таблица my_test_table :

create table my_test_table (a number, b number);

, которая наполнилась какими-то данными:

declare
  i number:=0;
begin
 while i < 1000 
 loop
 insert into my_test_table (a, b) values (i, i*100);
 i:=i+1; 
 end loop;
 commit;
end;

А потом мы с этими данными работаем. Они, как водится, апдейтятся, делитятся, вставляются. Может, просто вставляются. До того, как пришел бестолковый разработчик, у нас там была, ну, тысяча записей:

select count(*) from my_test_table;
1000

А бестолочь выполнила запрос:

delete from my_test_table where a between 600 and 800; commit; 

201 rows deleted

Считаем количество записей после удаления:

select count(*) from my_test_table; 
799

Вытащить из флэшбэков удаленные записи, можно вернувшись к тому моменту одним из двух способов:
1. вернуться в прошлое на системный SCN (system change number)
посмотреть его можно так:

  dbms_flashback.get_system_change_number
  

вернуться к нему можно так:

  dbms_flashback.enable_at_system_change_number
  

2. вернуться в прошлое на какой-то таймштамп. Например, минут 5 назад:

  dbms_flashback.enable_at_time(sysdate - interval '5' minute)
  

Так как нам достоверно известно, что записи были грохнуты 5 минут назад, то вернемся именно на тот момент. Так как при работе с флэшбэками DDL/DML операции невозможны (рассогласования базы данных никому не нужны, кроме той самой бестолочи), то сделаем пустой слепок таблицы:

create table my_test_table_recover as select * from my_test_table where rownum=0;

Время вытаскивать нас из жопы:

DECLARE

 TYPE my_array IS TABLE OF my_test_table%ROWTYPE;
 my_data my_array;

 CURSOR flash_cur IS SELECT * FROM my_test_table;
 flash_rec flash_cur%ROWTYPE;
 BEGIN
   dbms_flashback.enable_at_time(sysdate - interval '5' minute);
   OPEN flash_cur;
   dbms_flashback.disable;

   LOOP
     FETCH flash_cur BULK COLLECT INTO my_data;

     FORALL i IN 1..my_data.COUNT
     INSERT INTO my_test_table_recover VALUES my_data(i);

     EXIT WHEN flash_cur%NOTFOUND;
   END LOOP;
   CLOSE flash_cur;
   COMMIT;
 END;
 /

Смотрим что получилось:

select count(*) from my_test_table_recover
1000

Вуаля.

Следует помнить, что ретроспективный запрос ограничен периодом хранения флэшбэков.

P.S. на постгресе такой фокус не пройдет, потому что журналы транзакций (WAL), конечно, есть, и горячий резерв можно организовать через них, есть и откат к определенному моменту (pg_xlog), но это откат всех баз, который врядли нужен и едва ли не сделает все еще хуже. Иными словами, ретроспективные запросы на слонике - невозможны.

Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.5 Build:#805 Apr 26, 2007) - Запрос Bug/feature - Связаться с администраторами