В очередной раз об ORA-00600: Internal message code, arguments: [01578] [...] [...] [] [] []. ORA-01578: Oracle data block corrupted (file ..., block ...)

dbstalker, 15 июля

Когда встречается такое повреждение блока данных базы Oracle, первым делом определяемся с именем и типом сегмента, которому принадлежит поврежденный блок. Чаще всего блок может принадлежать либо табличному, либо индексному сегменту.

Если сегмент индексный, то проблема решается очень быстро. Об этом на блоге писалось неоднократно: так как данные в таблице полностью доступны, удаляем индекс (drop) и пересоздаем его (create). А поврежденный блок будет переформатирован, когда он будет востребован.

Если же сегмент табличный, то есть несколько вариантов для решения этой проблемы:

  • Используя backups и archived redo log , можно сделать recovery того блока или того файла базы данных, который содержит поврежденный блок. Но с маленькой оговоркой: блок данных еще не был поврежден тогда, когда производилось резервное копирование. Недостаток этого варианта: очень много времени и телодвижений. ?
  • Если есть свеженький дамп поврежденной таблицы, можно сделать ее импорт. Только нужно удалить испорченную таблицу перед выполнением импорта.
  • Если предыдущие варианты, по каким либо причинам не подходят, можно попробовать восстановить данные таблицы путем некоторых манипуляций. О них и пойдет речь далее.

Предлагаю попробовать выбрать записи таблицы, которые НЕ находятся в поврежденном блоке. Попытаемся извлечь, используя для этого псевдостолбец "идентификатор записи" (rowid).

Логика приблизительно такая:

1. file#=номер_файла block#=номер_блока -- наши исходные данные о сбойном блоке, взяты из сообщения об ошибке.

2. SELECT SEGMENT_TYPE,OWNER,SEGMENT_NAME FROM DBA_EXTENTS WHERE FILE_ID = номер_файла AND номер_блока BETWEEN BLOCK_ID AND BLOCK_ID+BLOCKS -1 -- находим название, владельца и тип сегмента.

3. select DATA_OBJECT_ID from dba_objects where object_name=&&SEGMENT_NAME and owner=&&OWNER --находим DATA_OBJECT_ID нашей таблички по данным полученным в предыдущем запросе.

4. select substr(dbms_rowid.rowid_create(1,&& DATA_OBJECT_ID, номер_файла,номер_блока,1),1,15) r_rowid from dual -- находим первые 15 знаков ROWID записей в поврежденном блоке( они общие для всех записей блока). Остальные 3 знака ROWID – для каждой записи, находящейся в этом блоке, свои.

5. create table таблица_rowid_not_corruption as select rowid rowid_not_corr from таблица where rowid not like &&r_rowid||'%' – создаем таблицу, содержащую все ROWID записей, которые находятся вне поврежденного блока.

6. select * from таблица where rowid in (select rowid_not_corr from таблица_rowid_not_corruption ) – выбираем все записи с „хорошими” ROWID.

Записи сохраняем в промежуточной таблице.

Вся вышеизложенная логика хороша при одном условии, что в пунктах 5 и 6 оракл не будет выполнять полное сканирование поврежденной таблицы. Для этого нужно поработать с настройкой этих запросов. Если есть индексы, то нужно запросы настроить так, чтобы они использовались.

Может быть, у вас есть более надежные и простые способы извлечения данных из поврежденной таблицы?

P.S. Думаю будет лучше, если 4-6 пункты заменить на:

4. select dbms_rowid.rowid_create(1,&&DATA_OBJECT_ID,номер_файла,номер_блока,0) first_rowid from dual -- находим ROWID первой записи в поврежденном блоке

5.select dbms_rowid.rowid_create(1,&&DATA_OBJECT_ID,номер_файла,номер_блока+1,0) last_rowid from dual -- находим ROWID первой записи в блоке, следующем за поврежденным

6.CREATE TABLE временная таблица AS SELECT /*+ ROWID(A) */ * FROM from таблица А where rowid < &&first_rowid; -- создаем таблицу из записей поврежденной таблицы, находящихся ДО поврежденного блока;

7.INSERT INTO временная таблица SELECT /*+ ROWID(A) */ * FROM таблица А where rowid >= &&last_rowid; -- добавляем в таблицу записи из поврежденной таблицы, находящихся ПОСЛЕ поврежденного блока.

Надеюсь, вы заметили хинт /*+ ROWID(A) */, который заставляет оракл не выполнять полное сканирование таблицы, а работать с ROWID.

И еще. Cмотрим сюда и видим подходящие события:

10231	skip corrupted blocks on _table_scans_
10232	dump corrupted blocks symbolically when kcbgotten
10233	skip corrupted blocks on index operations

Например, выполнив команду

alter session set events '10231 trace name context off'; 

отключаем проверку всех поврежденных блоков в сессии.

Надеюсь вы осознаете все последствия данного действия?

 

Новый комментарий

Я не спамер: введите суму 3+9



 

От авторов блога

О Блоге - прочитай перед началом.

Задать вопрос и получить ответ - уже решено 94 вопросов

Глоссарий - список терминов и сокращений


 
 

Бизнес форум

Последние темы:

Телепрограмма
23 июня, 1 ответа
Турция
23 июня, 4 ответа
Выбор люстры
22 июня, 1 ответа