Пользователь
0,0
рейтинг
12 декабря 2012 в 13:05

Разработка → Восстановление битых блоков в Oracle — LOB сегмент из песочницы

В один прекрасный момент в алерт-логе очень большой БД, начали появляться сообщения следующего содержания:
Corrupt block relative dba: 0x0724c078 (file 28, block 2408568)
Fractured block found during backing up datafile
Reread of blocknum=2408568, file=E:\ORACLE\ORADATA\XXX\XXX_BLOB16.DBF. found same corrupt data

Ситуация осложнялось тем, что бэкапов под рукой не было.
Далее последуют инструкции по выходу из данной ситуации.


RMAN упирался в данный блок и ни в какую не хотел бэкапить базу.
Начался детальный разбор полетов, и выяснение к чему относится данный блок:
SELECT owner, segment_name, segment_type 
FROM dba_extents 
WHERE file_id = 28 
AND 2408568 BETWEEN block_id AND block_id + blocks - 1;

OWNER
----------------------------
SEGMENT_NAME
----------------------------
SEGMENT_TYPE
------------------
DOC_USER
SYS_LOB0000075021C00003$$
LOBSEGMENT

Далее было выяснено к какой таблице относился данный LOB сегмент:
SELECT table_name, column_name 
		  FROM dba_lobs 
		 WHERE owner='DOC_USER'
		   AND segment_name='SYS_LOB0000075021C00003$$';

TABLE_NAME
-------------------
COLUMN_NAME
-------------------
DOC_LARGE_PIC
BINARY_DATA

DBMS_REPAIR — не смог прояснить ситуации, ввиду ограничений на работу с LOB полями.

На просторах сети было найдено решение — суть его заключалась в следующем:
  • 1. Поочередно перебрать записи из таблицы.
  • 2. При попадании в запись, относящейся к битому блоку выдернуть ее ROWID.


set serverout on
		exec dbms_output.enable(100000);
		declare
		 error_1578 exception;
		 pragma exception_init(error_1578,-1578);
		 n number;
		 cnt number:=0;
		 badcnt number:=0;
		begin
		  for cursor_lob in
		        (select rowid r, BINARY_DATA L from DOC_USER.DOC_LARGE_PIC)
		  loop
		    begin
		      n:=dbms_lob.instr(cursor_lob.L,hextoraw('AA25889911'),1,999999) ;
		    exception
		     when error_1578 then
		       dbms_output.put_line('Got ORA-1578 reading LOB at '||cursor_lob.R);
		       badcnt:=badcnt+1;
		    end;
		    cnt:=cnt+1;

		  end loop;
		  dbms_output.put_line('Scanned '||cnt||' rows - saw '||badcnt||' errors');
		end;
		/


Скрипт успешно вернул две записи:

Got ORA-1578 reading LOB at AAASUNAAQAAPf7hAAY
Got ORA-1578 reading LOB at AAASUNAAQAAPf7hAAp


При помощи нехитрого запроса были получены PRIMARY KEY данных записей и записи были успешно потерты.

Казалось бы, вот оно решение проблемы — но RMAN упорно не хотел резервировать базу упираясь в данные блоки.
Запрос в V$DATABASE_BLOCK_CORRUPTION и RMAN VALIDATE DATAFILE подтвердили о том, что блоки остались в прежнем состоянии.

Не очень хотелось создавать таблицу и забивать ее под завязку всего табличного пространства, поэтому было принято решение использовать ALTER TABLE XXX SHRINK SPACE.

ALTER TABLE DOC_USER.DOC_LARGE_PIC ENABLE ROW MOVEMENT;
ALTER TABLE DOC_USER.DOC_LARGE_PIC SHRINK SPACE CASCADE;


Затем запускаем проверку проблемного файла RMAN'ом:
RMAN VALIDATE DATAFILE 28;

После данной операции представление V$DATABASE_BLOCK_CORRUPTION оказалось кристально чистым.
Далее база была успешно зарезервирована RMAN'ом а недостающие записи были выдернуты из реплики.

UPDATE

Данная проблема возникла после того как начали рассыпаться диски на сервере.
Копию раздела сняли сторонней утилитой и развернули на новый свежесобранный массив.
Все операции проводились на базе весом 1,5 Тб.
Вес таблицы 70 Гб.
Версия Oracle 11g R2 — думаю данный способ применим и для 10g.
ALTER TABLE… SHRINK SPACE CASCADE имеет ряд ограничений предварительно рекомендую ознакомится с документацией перед его использованием.
Александр @proger89
карма
2,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (9)

  • 0
    1. Укажите версии Oracle, к которым применимы эти советы
    2. Неплохо бы указать и ограничения для SHRINK SPACE, для полноты статьи.
    3. Раз у вас появились fractured блоки, то могут появиться и новые в процессе SHRINK.

    В общем, нужно хорошо подумать прежде, чем.
    • 0
      Спасибо за комментарий! Изменения внес и кратко описал ситуацию предшествующую данной проблеме. По пункту 3 — в данном случае блоки имели логическое повреждение.
  • 0
    Сколько шли альтеры и какой примерно размер базы?
    • 0
      Около минуты.
      • 0
        Интересно, какой размер таблицы?
  • +1
    Вес таблицы 70 Гб.
    • 0
      А если был бы бэкап и редо, было бы проще?
      • 0
        Значительно проще — можно было бы просто запустить:
        RMAN BLOCKRECOVER CORRUPTION LIST.
        Либо явно подсунуть ему датафайл и указать поврежденные блоки:
        RMAN BLOCKRECOVER DATAFILE 28 BLOCK 2408568
        • 0
          Забыли указать мельчайшую деталь — фича RMAN Block Recover есть только в Oracle EE (Enterprise Edition). А это, на базе в 1.5 ТБ, которая скорее всего управляется не одним десятком CPU (или хотя бы ядер) — сотни тысяч $$ (для любопытствующих — прикинуть стоимость лицензий можно тут: orashop.ru)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.