Oradebug: работа с дампами, вывод и отладка в Oracle

oradebug - утилита для получения дампов и отладки в базе данных OracleВ этой статье я коротко расскажу о методах создания дампов базы данных, демонстрирующих те или иные особенности работы Oracle.

Существует множество способов воздействия одного сеанса на другой. Одним из старейших и простейших является утилита oradebug, которую можно использовать в своих интересах, имея привилегии sysdba. Многое из того, что позволяет oradebug, можно сделать путем установки событий, поэтому некоторые из приемов, перечисленных в этом разделе, будут появляться в разных обличьях далее.


Оглавление статьи[Показать]


 

Приостановка процессов

При изучении особенностей процессов dbwr и lgwr мне иногда приходилось приостанавливать их. Утилита oradebug позволяет приостанавливать и возобновлять процессы. Первое, что нужно сделать для этого, – присоединиться к процессу Oracle, для чего я использую идентификатор процесса (pid) из v$process. Можно написать множество разных запросов для поиска идентификаторов фоновых процессов, и ниже приводится пример такого запроса, который будет работать во многих версиях Oracle (однако, в версиях 10g и выше имеются более простые способы): 

select
      prc.pid
from
      v$bgprocess bgp,
      v$process prc
where
      bgp.name = ‘LGWR’
      and prc.addr = bgp.paddr
;

В системе, которая прямо сейчас у меня под рукой, этот запрос вернул значение 6, которое я могу использовать далее (внимание: не делайте этого в системе, где работает еще кто-то кроме вас – иногда может произойти аварийное завершение экземпляра или у вас может не получиться возобновить процесс): 

SQL> oradebug setorapid 6
Windows thread id: 1052, image: ORACLE.EXE (LGWR)
SQL> oradebug suspend
Statement processed.
SQL> -- запустите другой сеанс, выполните какую-либо операцию
SQL> -- и подтвердите транзакцию, сеанс "зависнет", ожидая
SQL> -- завершения синхронизации файла журнала.
SQL> oradebug resume
Statement processed.
SQL>

Приостановка процесса lgwr является достаточно опасной операцией. Не забывайте, что некоторый рекурсивные запросы SQL могут приостанавливать сеансы в ожидании завершения записи в журнал. Например, если включен аудит базы данных командой audit connect, любые пользовательские сеансы, пытающиеся установить или разорвать соединение, зависнут на попытке подтвердить вставку записи в таблицу sys.aud$.

Механизм приостановки я использовал, например, чтобы убедиться, что одно из моих долгих предположений (локальные взаимоблокировки внутри экземпляра обнаруживает процесс pmon) было неверным. Я приостановил процесс pmon, создал ситуацию взаимоблокировки и дождался ошибки ORA-00060 «Deadlock detected». Этот эксперимент наглядно показал, что даже при остановленном процессе pmon, взаимоблокировки обнаруживаются системой в течение (стандартных) 3 секунд.

 

Вывод дампов

Утилиту oradebug можно использовать для вывода содержимого структур в памяти в файлы трассировки. Для этого я обычно подключаюсь как sys и затем присоединяю oradebug к моему собственному процессу, чтобы получить интересующие меня дампы. В oradebug есть команда, возвращающая имя файла трассировки, но, похоже, что она работает только после вывода первой порции информации в этот файл. Поддерживается также возможность изменить имя файла трассировки, установив параметр tracefile_identifier

SQL> oradebug setmypid
Statement processed.
SQL> oradebug tracefile_name
Statement processed.
SQL> alter session set tracefile_identifier = xxx;
Session altered.
SQL> oradebug tracefile_name
c:\oracle\admin\d10g\udump\d10g_ora_2256_xxx.trc
SQL>

Чтобы получить список всех доступных дампов, можно воспользоваться командой oradebug dumplist. Многие команды dump принимают два параметра – имя дампа и уровень. Уровень дампа может интерпретироваться двояко: в первом случае более высокое значение уровня дампа означает вывод более подробной информации; во втором уровень используется как набор битовых флагов, где разные степени двойки соответствуют разным данным. В табл. П.1 перечислены параметры команды dump. Этот перечень верен для версий 10g+.

Параметр Результат
buffers N Выводит информацию о буферах, заголовках буферов и разных связанных списках. Любой дамп с уровнем выше 1 наверняка будет огромен, даже если кэш буферов невелик. Для кэша 8 Мбайт я получил дамп объемом 28 Мбайт на уровне 2 и 49 Мбайт на уровне 3. К сожалению, только на уровне 4 выводится вся информация о связанных списках в рабочем наборе данных sets. 1 = только заголовки буферов 2 = 1 + дампы блоков + заголовки транзакций 3 = 2 + полный символический дамп блоков 4 = рабочие наборы данных, заголовки блоков и дампы блоков в порядке их следования внутри хэш- цепочек
enqueues N Выводит информацию о ресурсах и блокировках. Наиболее ценная информация выводится на уровне 3 (но требует небольшого форматирования, чтобы исключить путаницу). Объем вывода в значительной степени зависит от текущего числа строк в v$lock и редко достигает 1 Мбайта 1 = хэш-таблица ресурсов в очереди 2 = 1 + список используемых ресурсов 3 = 2 + активные блокировки на каждом ресурсе
file_hdrs N Выводит информацию о заголовках файлов с данными. Здесь не так много полезной информации, но если вы захотите проверить эффект контрольных точек, вы сможете вывести дампы заголовков файлов, чтобы увидеть номера SCN контрольных точек. Для каждого файла с данными выводится несколько килобайт. 1 = стандартный 2 = дополнительная информация о заголовках в стиле версии 10 3 = дополнительная информация о табличных пространствах и расширенная информация о файлах. На этом уровне можно также увидеть root dba: – элемент в файле 0, определяющий местоположение таблицы sys.bootstrap$.
redohdr N Выводит информацию о заголовках файлов оперативного журнала. На уровнях с 1 по 3 выводится все более подробная информация. Уровня 1 достаточно, чтобы получить первый и следующий номер SCN. 1 = стандартный 2 = дополнительная информация о совместимости заголовка файла 3 = дополнительные подробности
controlf N Выводит содержимое управляющего файла. На уровне 10 выводится полный, неформатированный дамп, на уровнях с 1 по 9 и на уровне 11 выводится все более подробная информация о разных записях в управляющем файле. На уровне 2 можно получить некоторые важные номера SCN и RBA (Redo Block Addresses – адреса блоков повторения).
library_cache N Выводит информацию о библиотечном кэше. Здесь уровень используется как набор битовых флагов, определяющих, какая информация будет выводиться. Странно, но некоторые дампы в 11g содержат меньше информации, чем аналогичные дампы в 10g. 1 = v$librarycache (примерно) и (в 10g) сводка объемов памяти выделенных для ключевых структур 2 = сводка о хэш-цепочках и (в 10g) сводка объемов памяти выделенных для постоянного пользования 4 = список хэш-блоков с заголовками структур и связанные списки в хэш-цепочках (достаточно, чтобы увидеть информацию о блокировках/закреплениях/мьютексах для объектов) 8 = 4 + зависимости, блоки «данных», счетчики обращений и т. д. 16 = 8 + дампы кучи для каждого блока «данных» объекта; дамп получается очень объемным 32 = 16 + полный дамп всех фрагментов в кучах; дамп получается гигантским {x$kglob.kglhdadr} (например, v$sql.child_address). Для версий ниже 11g, если преобразовать адрес объекта (дочернего) в десятичное представление, можно вывести сводную информацию для объекта. Если вы собираетесь использовать шестнадцатеричные адреса, полученные из структур x$ или v$, их необходимо предварять префиксом «0x». {x$kglob.kglhdpar} (например, v$sql.address). Для версий ниже 11g, если преобразовать адрес объекта (родительского) в десятичное представление, можно вывести сводную информацию для объекта с коротким списком дескрипторов дочерних объектов. И снова, при использовании адресов в шестнадцатеричном представлении, их необходимо предварять префиксом «0x».
library_cache_object {level} {address} Только для версии 11.2 (распознается в версии 11.1, но всегда завершается с ошибкой «in-flux». Является заменой для 11g дампа уровня объектов в 10g. Выводит информацию о единственном объекте в библиотечном кэше. Адрес должен быть {x$kglob. kglhdadr} (например, v$sql.child_address) или {x$kglob.kglhdpar} (например, v$sql.address). Адреса в шестнадцатеричном представлении должны предваряться префиксом «0x» или преобразовываться в десятичный формат. Уровень используется как набор битовых флагов, определяющих, какая информация будет выводиться; наиболее полезными, на мой взгляд, являются следующие уровни: 0 – простой, короткий дамп 16 – подробный дамп 48 – чрезвычайно подробный дамп, включающий информацию о дочерних объектах, если имеются
heapdump N Выводит содержимое кучи верхнего уровня. И снова, уровень используется как набор битовых флагов, определяющих, какая информация будет выводиться. В данном случае каждый бит представляет разную кучу. Наибольший интерес для меня представляет дамп кучи SGA со списком хэш-цепочек свободных фрагментов памяти и списками LRU используемых фрагментов. Будьте осторожны, применяя эту команду для просмотра содержимого SGA, – она может подвесить систему или вызвать существенные проблемы конкуренции за защелки на несколько минут. 1 = дамп кучи PGA 1025 (0x401) = куча PGA с дампами фрагментов памяти 2 = дамп кучи SGA 2050 (0x802) = куча SGA с дампами фрагментов памяти 4 = дамп кучи сеанса (UGA) 4100 (0x1004) = куча сеанса с дампами фрагментов памяти 8 (8200/0x2008) = куча текущего вызова (с дампами фрагментов памяти) 16 (16400/0x4010) = куча пользовательского вызова (с дампами фрагментов памяти) 32 (32800/0x8020) = большая куча пула (с дампами фрагментов памяти) 64 (65600/0x10040) = куча пулов потоков (с дампами фрагментов памяти) 128 (131200/0x20080) = куча пула Java (с дампами фрагментов памяти) Можно также добавить степень power(2,29) = = 0x2000,0000 = 536,870,912 к базовому номеру кучи, чтобы получить более подробную информацию о верхней пятерке подобластей в куче, и степень power(2,30) = 0x4000,0000 = 1,073,741,824, чтобы получить рекурсивный дамп верхней пятерки подобластей в каждой подобласти в дампе.

 

Вывод содержимого памяти

Для исследования содержимого конкретных областей памяти я использую две основные стратегии. Если известно имя переменной Oracle, ее содержимое можно посмотреть с помощью команды dumpvar. Например, я знаю, что в SGA существует переменная с именем kcbnhb (kcb – кэш буферов, nhb – число хэш-блоков), значение которой можно получить следующим образом:

SQL> oradebug setmypid
Statement processed.
SQL> oradebug dumpvar sga kcbnhb
uword kcbnhb_ [3D387B4, 3D387B8) = 00008000
SQL>

В общем случае эта команда имеет синтаксис dumpvar {area} {variable}. Соответственно, зная, к примеру, что текущее значение для use_stored_outlines хранится в переменной ugauso_p, я могу выполнить следующую команду: 

SQL> alter session set use_stored_outlines = rule_based;
Session altered.
SQL> oradebug setmypid
Statement processed.
SQL> oradebug dumpvar uga ugauso_p
qolprm ugauso_p [7867A44, 7867A68) = 00000001 5552000A 425F454C 44455341
SQL>

Если вы знакомы с шестнадцатеричными числами и кодами ASCII, вы сможете увидеть в последних 12 байтах дампа текст «RULE_BASED», начинающийся со значения длины 10 (0x000A).

Если потребуется найти имена переменных в SGA, можно выполнить запрос к структуре x$ksmfsv (в этом примере я выбрал лишь подмножество имен, потому что полный их перечень насчитывает несколько тысяч) и попытаться угадать, что означают имена и типы найденных переменных: 

select
*
from x$ksmfsv
where ksmfsnam like ‘kcbn%’
;
ADDR      INDX INST_ID     KSMFSNAM KSMFSTYP KSMFSADR KSMFSSIZ
-------- ----- ------- ------------ -------- -------- --------
034F9E50  2285       1 kcbnbh_      word     03D37B28        4
034F9E60  2286       1 kcbnbha_     word *   03D37B2C        4
034F9E80  2288       1 kcbnwp_      word     03D37B34        4
034FAF00  2552       1 kcbnbf_      word     03D387B0        4
034FAF10  2553       1 kcbnhb_      uword    03D387B4        4
034FAF20  2554       1 kcbnhbsft_   uword    03D387B8        4
034FB090  2577       1 kcbnpg_      ub4      03D38814        4
034FB160  2590       1 kcbnchkl_    ub1      03D38868        1
034FB170  2591       1 kcbnchk_     int      03D3886C        4
034FBA40  2732       1 kcbnf01_     uword    03D38CE0        4
034FBA50  2733       1 kcbnf02_     uword    03D38CE4        4

Каждая строка в x$ksmfsv хранит начальный адрес переменной (обратите внимание, что имена в столбце KSMFSNAM оканчиваются символом подчеркивания, который нужно удалить перед использованием в команде dumpvar).


Примечание. Если вы не хотите обращаться к x$ksmfsv (к слову сказать, это служба ядра, позволяющая получить информацию о фиксированных переменных в SGA), можно воспользоваться специальной командой для получения тех же переменных и эквивалентных структур в PGA и UGA: oradebug dump global_area N, где значение N (по аналогии с командой heapdump в табл. П.1) равное 1 соответствует PGA, 2 – соответствует SGA и 4 соответствует UGA. (Чтобы одновременно получить дамп структур, на которые ссылаются различные указатели в этих переменных, соответствующее значение N можно умножить на 1025.)


oradebug - дампы (dump) и отладка в СУБД Oracle

С помощью dumpvar можно обращаться к переменным по именам, но большинство из этих переменных являются простыми числами (точнее, указателями на числа), поэтому у нас есть еще две стратегии, упрощающие доступ к ним. Во-первых, можно получить адрес – не забывайте, что они отображаются в шестнадцатеричном виде. Например, ниже показан еще один способ проверки числа хэш-блоков: 

SQL> oradebug setmypid
Statement processed.
SQL> oradebug peek 0x03D387B4 4
[3D387B4, 3D387B4) = 00008000

Команда peek принимает два обязательных параметра и один необязательный. Первые два – это адрес и длина, последний – флаг, сообщающий Oracle о необходимости вывести дамп в файл трассировки. В данном примере я потребовал вывести 4 байта (минимальное число для данной платформы), но не отправлять результат в файл трассировки.

Однако, имея адрес, можно запросить содержимое памяти непосредственно. Структура x$ksmmem является картой памяти SGA, поэтому можно запросить сразу 4 байта памяти. Ниже показано, как иначе запросить число хэш-блоков: 

SQL> select * from x$ksmmem where addr = hextoraw(‘3D387B4’);
ADDR       INDX INST_ID KSMMMVAL
-------- ------ ------- --------
03D387B4  12069       1 00008000
1 row selected.

Будьте осторожны, используя x$ksmmem. Если указать адрес, который в настоящий момент отсутствует в списке, сеанс завершится аварийно с ошибкой ORA-03113, «end-of-file on communication channel» (ORA-03113, «принят сигнал конца файла по коммуникационному каналу»). То же самое произойдет, если инструкция SQL попытается выполнить предикат, который Oracle не сможет превратить в addr = raw_value.

Возможность непосредственного получения содержимого памяти может показаться сильно ограниченной, но имейте в виду, что это не самый лучший способ обращения к памяти, именно поэтому некоторые компании (и предприимчивые разработчики) создают низкоуровневые утилиты, подключающиеся напрямую к памяти Oracle для ее чтения. Я иногда испытывал необходимость проверить содержимое буфера журнала, что послужило для меня неплохим началом.

Следующая инструкция SQL извлекает некоторую информацию об общедоступных потоках журналирования: 

select
       first_buf_kcrfa,
       last_buf_kcrfa,
       pnext_buf_kcrfa_cln,
       next_buf_num_kcrfa_cln
from
       x$kcrfstrand
where
       last_buf_written_kcrfa != ‘00’
order by
       indx
;
FIRST_BU LAST_BUF PNEXT_BU NEXT_BUF_NUM_KCRFA_CLN
-------- -------- -------- ----------------------
05450000 057A4800 05552E00                   2070
057A4A00 05AF9200 05AF9400                   6820
2 rows selected.

Значения FIRST_BUF_KCRFA и LAST_BUF_KCRFA – это адреса первого и последнего буферов (то есть, страниц, размер которых соответствует размеру блоков в файле журнала) из двух общедоступных буферов журнала в моей системе. Значение PNEXT_BUF_KCRFA – это адрес следующего буфера, который будет использован и записан на диск. Имея эту информацию, я мог бы с некоторыми усилиями (после получения некоторых, легко идентифицируемых данных в буфере журнала) извлечь содержимое буфера журнала с помощью oradebug. Так как каждая страница в буфере журнала занимает 512 байт (что больше, чем Oracle может отобразить на экране) я обычно использую команду oradebug peek {address} 512 1 для вывода данных в файл трассировки, по одной странице за раз. Я написал следующие команды, которые выводят содержимое только первых 16 байт следующих нескольких страниц в буфере, которые являются байтами заголовка страницы:

SQL> oradebug peek 0x05552e00 16
[5552E00, 5552E10) = 00002201 000022BE 000002E9 D67F80A8
SQL> oradebug peek 0x05553000 16
[5553000, 5553010) = 00002201 000022BF 000002E9 9B6B8010
SQL> oradebug peek 0x05553200 16
[5553200, 5553210) = 00002201 000022C0 000002E9 509980D0
SQL>

Обратите внимание, что третье слово в каждой странице (000002e9, десятичное значение 745) – это sequence# моего текущего журнала. Второе слово – это идентификатор блока в файле журнала, соответствующего данной странице в памяти. (К сожалению, я не знаю, что означает первое слово 00002201.) Наибольший интерес для меня представляли данные и их сопоставление с содержимым символического дампа из файла, о котором я расскажу чуть ниже.

 

Вывод дампа из инструкций SQL

Многие команды утилиты oradebug для вывода структур доступны также в SQL*Plus, иногда с параметрами, помогающими отфильтровать содержимое дампа. Многие дампы, из представленных в предыдущем разделе, можно получить вызовом alter session или с помощью пакета dbms_system. Далее будут представлены дампы, которые можно получить вызовом alter system.

 

Альтернативы oradebug

Если по каким-то причинам вы не хотите использовать oradebug, ниже приводится ограниченное, альтернативное решение, демонстрирующее, как получить дамп кэша буферов в обычном сеансе SQL*Plus: 

alter session set tracefile_identifier = ‘alter_session’;
execute dbms_system.ksdwrt(1,’Example using alter session’)
alter session set events ‘immediate trace name buffers level 1’;

Обычно я стараюсь добавить в дамп с данными некоторые текстовые комментарии. Для этого можно воспользоваться процедурой dbms_system.ksdwrt. Она принимает два параметра: второй – это фрагмент текста, а первый сообщает Oracle, куда вывести текст. В числе возможных вариантов: 1 – файл трассировки, 2 – журнал предупреждений (alert log) и 3 – оба предыдущих варианта.

Обычная попытка вывести дамп с помощью oradebug превращается в событие immediate, со словом level между именем дампа и его уровнем.

Примечание. Многие команды oradebug dump имеют эквиваленты на языке SQL, однако есть такие комбинации, которые на SQL не работают. Например, команда oradebug dump library_cache {address} для вывода информации об отдельном объекте в библиотечном кэше. Попытавшись, вы получите пустой файл трассировки с единственной строкой «In-flux value for handle» (изменчивое значение дескриптора).

Возможно вы уже знакомы с процедурой dbms_system.set_ev(), как одного из множества способов включения sql_trace (или, как его часто называют, событие 10 046). Однако, имеется фиктивное событие (с номером 65 535), которое можно использовать для получения именованных дампов: 

alter session set tracefile_identifier = ‘dbms_system’;
execute dbms_system.ksdwrt(1,’Example using dbms_system’)
declare
        m_serial     number(15,0);
begin
        select serial#
        into m_serial
        from v$session
        where sid = dbms_support.mysid
        ;
        dbms_system.set_ev(
        si => dbms_support.mysid,
        se => m_serial,
        ev => 65535,
        le => 1,
        nm => ‘buffers’
);
end;
/

Пять параметров процедуры dbms_system.set_ev имеют полные имена: sid, serial#, event, level и name. При передаче в параметре event значения 65 535, в параметрах name и level можно указать имена и уровни команд oradebug.

 

Блоки файлов данных

Первая из команд alter system, которые я регулярно использую (часто завернутые в процедуру PL/SQL для идентификации корневых индексных блоков или заголовков сегментов блоков), выводит содержимое блока или группы блоков. Она имеет следующий синтаксис: 

alter system dump datafile {File no} block {Block no};
alter system dump datafile 4 block 129;
alter system dump datafile {File no} block min {Block min} block
max {Block max};
alter system dump datafile 4 block min 129 block max 133;

В последних версиях Oracle эта команда выведет содержимое дисковые копии выбранных блоков и все копии в памяти и, благодаря сложности механизма приватного журналирования, может отмечать одну копию из памяти, как поврежденную. Ниже приводится вариант этой команды, в которой используется имя файла данных вместо его номера: 

alter system dump datafile ‘{name}’ block {Block no};
alter system dump datafile ‘{name}’ block min {Block min} block max
{Block max};

При использовании этой версии команды, блоки будут читаться с диска (это означает, что вам придется выполнить контрольную точку, чтобы получить последнюю версию данных).

С помощью команд выше можно получить содержимое практически любого блока в файле данных (я знаю только одно исключение – заголовки файлов – но могут быть и другие), однако есть специальный случай, который я иногда использую при работе с заголовками undo-сегментов для вывода дампа блока по имени сегмента: 

alter system dump undo header ‘{segment name}’;
alter system dump undo header ‘ _SYSSMU3$’;

 

Файлы журнала

Также достаточно регулярно я создаю дампы файлов журнала. Базовый синтаксис прост:

alter system dump logfile ‘{filename}’;
alter system dump logfile ‘C:\ORACLE\ORADATA\D10G\REDO01.LOG’ 

В большинстве случаев я имею обыкновение выполнять команду alter system switch logfile; перед работой и затем выводить дамп всего файла. Но, вообще говоря, имеется возможность выбирать, какие фрагменты информации извлекать из файла. В приложении My Oracle Support (прежде известное как MetaLink) имеется примечание (ID 1031381.6), описывающее некоторые из возможностей. Однако упомянутой документ не полон. Насколько я знаю, полный синтаксис имеет вид:

alter system dump logfile ‘{filename}’
      scn min {first SCN to dump}
      scn max {last SCN to dump}
      time min {seconds since an oddly arbitrary point in time}
      time max {ditto}
      layer {integer}
      opcode {integer}
    xid {usn} {slot} {sequence} -- 10g и выше, не работает для IMU redo
    Objno {object id} -- 10g и выше, не работает для IMU redo
      dba min {datafile no} . {blockno} -- в 10g и выше уберите точку
      dba max {datafile no} . {blockno} -- в 10g и выше уберите точку
      rba min {log file seq#} . {blockno} -- в 10g и выше уберите точку
      rba max {log file seq#} . {blockno} -- в 10g и выше уберите точку

Как видите, команда имеет довольно широкий выбор параметров. Для себя наиболее полезными я считаю параметры, позволяющие определять блоки данных, а также идентификаторы объектов и транзакций. Мне приходилось использовать все остальные параметры на промышленных системах, кроме двух последних, определяющих адрес блока повторения. При работе с блоками отмены я предпочитаю получить дамп всех таких блоков, имеющих отношение к заданному блоку данных – обычно это помогает узнать, когда и как был поврежден блок данных.

Например, для 9i и 10g соответственно: 

alter system
        dump logfile ‘C:\ORACLE\ORADATA\D920\REDO02.LOG’
        dba min 11 . 10 dba max 11 . 10
;
alter system
        dump logfile ‘C:\ORACLE\ORADATA\D10G\REDO02.LOG’
        dba min 5 10 dba max 5 10
;

Обратите внимание на пробелы с обеих сторон от точки, которую необходимо добавлять в версиях Oracle 9i и ниже. Точка стала не нужна, начиная с версии 10g (то же относится к параметрам rba min и rba max). Помните также, что под номером файла ({datafile no}) здесь подразумевается абсолютный номер файла, а не относительный. Так как в небольших базах данных (насчитывающих не более 1023 файлов) абсолютные и относительные номера файлов обычно совпадают, вы можете установить событие 10 120 перед созданием пары файлов – это обеспечит присваивание файлам разных абсолютных и относительных номеров.

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

Я написал небольшой сценарий для вывода небольших периодов времени в прошлом (вы можете изменить его под свои нужды) – следующий код выводит дамп, соответствующий 5-минутному интервалу, который начинается за 10 минут до момента, как я закончил писать это приложение: 

select
       (
           (sysdate - 10/(24*60)) -
        to_date(‘25/7/1987 00:00:00’,’dd/mm/yyyy hh24:mi:ss’)
       ) * 86400 start_time,
       (
           (sysdate - 5/(24*60)) -
        to_date(‘25/7/1987 00:00:00’,’dd/mm/yyyy hh24:mi:ss’)
       ) * 86400 end_time
from
       dual
;
alter system
dump logfile ‘C:\ORACLE\ORADATA\D10G\REDO02.LOG’
           time min 760100786
           time max 760101086
DUMP OF REDO FROM FILE ‘C:\ORACLE\ORADATA\D10G\REDO02.LOG’
Opcodes *.*
RBAs: 0x000000.00000000.0000 thru 0xffffffff.ffffffff.ffff
SCNs: scn: 0x0000.00000000 thru scn: 0xffff.ffffffff
Times: 08/25/2011 11:06:26 thru 08/25/2011 11:11:26

И последнее, о чем я хочу упомянуть, – пара уровень/код операции. Код 5.4 соответствует записи подтверждения. Коды делятся на две части: уровень и код в пределах уровня (в данном случае под «уровнем» не подразумевается наличие какой-то иерархии). Уровень 5 – это уровень управления транзакциями, уровень 10 – это уровень индекса, уровень 11 – это уровень таблицы, и так далее.


Примечание. Желающим поближе познакомиться с существующими уровнями и кодами операций я могу порекомендовать посетить сайт Юлиана Дайка (Julian Dyke), где приводится один из наиболее исчерпывающих списков кодов операций.


Иногда полезно знать, какого рода активность имела место в период времени, когда, как кажется, записи повторения создавались наиболее интенсивно. Я знаю людей, который писали программы на языке C, чтобы с их помощью читать файлы журналов и анализировать коды операций – и я должен признать, что однажды я сам пользовался такой программой – но, если вам потребуется сделать что-то в этом роде, вы всегда сможете вывести дамп журнала за определенный период и затем использовать какой-нибудь инструмент, подобный утилите grep, чтобы выбрать коды операций или, как я иногда делаю, прочитать файл во внешнюю таблицу и проанализировать ее содержимое средствами SQL или PL/SQL. Единственная проблема такого подхода заключается в том, что файл трассировки обычно получается огромным.

Ниже, например, демонстрируется попытка сформировать дамп, включающий только записи с кодом операции 10.11 (установка указателя на предыдущий листовой блок) – одной из нескольких операций, выполняемых при делении листового блока индекса, которая устанавливает связи между блоками. Вслед за командой приводится несколько первых строк вывода команды find в Windows, выполняющей поиск текста «OP:10.11» в файле трассировки: 

alter system dump logfile ‘C:\ORACLE\ORADATA\D10G\REDO01.LOG’
layer 10 opcode 11 ;
---------- C:\ORACLE\ADMIN\D10G\UDUMP\D10G_ORA_3028.TRC
CHG #2 TYP:0 CLS: 1 AFN:5 DBA:0x01800c1b OBJ:88098 SCN:0x0.04a9ab0a
SEQ: 1 OP:10.11
CHG #2 TYP:0 CLS: 1 AFN:5 DBA:0x01800c1c OBJ:88098 SCN:0x0.04a9ab13
SEQ: 1 OP:10.11
CHG #2 TYP:0 CLS: 1 AFN:5 DBA:0x01800c1d OBJ:88098 SCN:0x0.04a9ab19
SEQ: 1 OP:10.11
CHG #2 TYP:0 CLS: 1 AFN:5 DBA:0x01800c1e OBJ:88098 SCN:0x0.04a9ab20
SEQ: 1 OP:10.11
CHG #2 TYP:0 CLS: 1 AFN:5 DBA:0x01800c1f OBJ:88098 SCN:0x0.04a9ab26
SEQ: 1 OP:10.11
CHG #2 TYP:0 CLS: 1 AFN:5 DBA:0x01800c20 OBJ:88098 SCN:0x0.04a9ab2d
SEQ: 1 OP:10.11

Я слегка отредактировал результаты, чтобы уместить их по ширине книжной страницы, но при этом я не удалял никакой информации. Здесь можно наблюдать два важных момента, которые выглядели бы подозрительными в промышленной системе. Во-первых, во всех строках фигурирует один и тот же объект OBJ – у нас имеется только один индекс, который растет. Во-вторых, значение DBA в каждой следующей строке увеличивается на один блок – каждый раз, когда в этот индекс добавляется блок, новый блок вставляется в индекс «слева» от предыдущего, а это означает, что данный индекс принимает множество данных по одной (или по несколько) строке за раз, в порядке убывания.

Я привел этот пример, только чтобы показать, насколько проще анализировать разные виды активности по отдельности, после извлечения подмножества записей повторения. В данном случае полный файл трассировки 5-минутного окна в файле журнала имел размер около 38 Мбайт, тогда как для данного конкретного кода операции его размер составил что-то около 160 Кбайт, что сделало возможным провести более детальные исследования.

И последнее замечание: если попытаться получить дамп для уровня 9999 и кода операции 9999, Oracle просканирует весь файл журнала, пытаясь найти код операции, который в действительности не существует, и тем самым проверит целостность файла.


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


 

Рекомендации

В заключение я хочу поделиться некоторыми своими соображениями, как можно разгадывать тайны Oracle, с теми, кто, продираясь через файлы трассировки и структуры X$, ломает голову над странными именами. Отличной отправной точкой для вас может послужить документ «175982.1 ORA-600 Lookup Error Categories» на сайте My Oracle Support (MOS), включающий большое число мнемоник, которые часто используются в качестве 3- и 4-буквенных префиксов в именах.

Удивительно, как много можно найти на MOS, имея пару подсказок – обычный поиск по коду ошибки базы данных позволит найти обходное решение, часто сопровождаемое небольшими фрагментами информации, поясняющими работу Oracle, или описаниями значений параметров, имеющих отношение к проблеме.

Наконец, пользуйтесь поиском в Интернете. Но помните: здесь есть источники достоверной информации, однако большая часть сведений (значительная доля которых находится на сайте MOS) – это всего лишь сплетни и предположения, накопившиеся за долгие годы. Информацию можно считать ценной, если она включает дату, версию Oracle и какие-либо подтверждающие сведения: это – три основных показателя, на которых должно основываться ваше доверие.

Вас заинтересует / Intresting for you:

Oracle и непроцедурный доступ ...
Oracle и непроцедурный доступ ... 8510 просмотров Antoni Tue, 21 Nov 2017, 13:32:50
Создание базы данных Oracle
Создание базы данных Oracle 34263 просмотров Александров Попков Wed, 14 Nov 2018, 12:44:39
Видеокурс по администрированию...
Видеокурс по администрированию... 10719 просмотров Илья Дергунов Mon, 14 May 2018, 05:08:47
Поддерживаемые Oracle типы дан...
Поддерживаемые Oracle типы дан... 9517 просмотров Валерий Павлюков Wed, 24 Oct 2018, 08:00:37
Войдите чтобы комментировать

ildergun аватар
ildergun ответил в теме #9294 5 года 4 мес. назад
Отличное руководство по работе Oradebug. Даже если автор и не автор... ;-)
VaaPa аватар
VaaPa ответил в теме #9099 5 года 8 мес. назад

Анонимный пишет: Добрый день! А о каких 8 главах идёт речь в начале этой статьи? Что-за книга?

Да, использовал книгу Ядро Оракл для написания этой статьи.
Daniil PR аватар
Daniil PR ответил в теме #9098 5 года 8 мес. назад
Ага, мне тоже интересно. Не вы автор? VaaPa, поделитесь откуда взяли материал?
 аватар
ответил в теме #9097 5 года 8 мес. назад
Добрый день! А о каких 8 главах идёт речь в начале этой статьи? Что-за книга?