Translate

суббота, 22 августа 2015 г.

Форматирование в Logdump

Кто работал с logdump, знает сколько команд необходимо выполнить, что получить удобное форматирование при просмотре trail-файлов. Можно поступить проще.
Необходимо создать файл logdump.frm в каталоге установки GoldenGate:
$ cd <GG_HOME> 
$ vim logdump.frm 
И вставить код:
FILEHEADER DETAIL 
GHDR ON 
DETAIL ON 
USERTOKEN DETAIL 
GGSTOKEN DETAIL 
RECLEN 128 
POS 0 
Открываете нужный вам файл и используйте команду obey:
Logdump 29 >open ./dirdat/xo000438 
Logdump 30 >obey logdump.frm

пятница, 7 августа 2015 г.

Диагностика работы БД

На продуктивной среде достаточно часто возникает необходимость в диагностике проблем работы системы. Это проблемные запросы, блокировки, сессии в состоянии rollback и т.п.
Приведу несколько полезных запросов для 11 версии Oracle и кластерной среды.

Запрос по поиску проблемных запросов:
select DBMS_SQLTUNE.REPORT_SQL_MONITOR(sql_id => sqlm.sql_id, type=>'TEXT', report_level=>'ALL', sql_plan_hash_value=>sqlm.sql_plan_hash_value, sql_exec_id=>sqlm.sql_exec_id) stat,
sqlm.* from gv$sql_monitor sqlm
where last_refresh_time > sysdate-10/(60*24)
and status = 'DONE (ERROR)'
order by sql_exec_start desc;

Поиск блокирующей сущность сессию
select a.inst_id, a.sid, a.serial#
from gv$session a, gv$locked_object b, dba_objects c
where b.object_id = c.object_id
and a.sid = b.session_id
and a.inst_id = b.inst_id
and OBJECT_NAME= :pObjectName;

Поиск сущности с блокировкой enq TM - contention:
SELECT l.sid, s.blocking_session blocker, SUBSTR(s.event,1,20),
l.type, l.lmode, l.request, o.object_name, o.object_type
FROM gv$lock l, dba_objects o, gv$session s
WHERE UPPER(s.username) = UPPER(:puser)
and l.type = 'TM'
AND l.id1 = o.object_id (+)
AND l.sid = s.sid and s.sid = :psid
ORDER BY sid, type;

Поиск блокирующих сессий:
select distinct
       o.object_name,
       sh.username || '(' || sh.sid || ',' || sh.serial# || ')' Holder,
       sh.osuser,
       sw.username || '(' || sw.sid || ',' || sw.serial# || ')' Waiter,
decode(lh.lmode,
              1,'null',
              2,'row share',
              3,'row exclusive',
              4,'share',
              5,'share row exclusive',
              6,'exclusive') Lock_Type
from v$session   sw,
     v$lock      lw,
     all_objects o,
     v$session   sh,
     v$lock      lh
where lh.id1 = o.object_id
      and lh.id1 = lw.id1
      and sh.sid = lh.sid
      and sw.sid = lw.sid
      and sh.lockwait is null
      and sw.lockwait is not null
      and lh.type = 'TM'
      and lw.type = 'TM';

Поиск взаимоблокирующих сессий:
select dbs.inst_id,
dbs.sid holding_sid, dbs.serial# holding_serial#, dbs.username holding_user,
       (select count(sid) from gv$session where blocking_session = dbs.sid and blocking_instance = dbs.inst_id) sessions_blocked,
       dbs.sql_id holding_sql_id, dbs.wait_class holding_class, dbs.event holding_event, dbs.seconds_in_wait holding_secs,
       dws.sid waiting_sid, dws.serial# waiting_serial#, dws.username waiting_user, dws.sql_id waiting_sql_id, dws.wait_class waiting_class, dws.event waiting_event, dws.seconds_in_wait waiting_secs
from gv$session dbs, gv$session dws
where dws.blocking_session = dbs.sid
and dws.blocking_instance = dbs.inst_id
order by dbs.sid, dws.seconds_in_wait desc

Поиск rollback-сессий:
SELECT s.username,
s.sid,
s.inst_id,
start_time,
used_ublk,
CASE
WHEN BITAND (flag, POWER (2, 7)) > 0 THEN 'RB in Progress'
ELSE 'Not Rolling Back'
END
AS "F Status",
sa.sql_text
FROM GV$TRANSACTION d, gv$session s, gv$sqlarea sa
WHERE s.saddr = D.SES_ADDR AND sa.sql_id = s.sql_id;

Запрос для определения последовательности операций выполняемых с кластера Weblogic. Полезен для оптимизации пользовательских запросов, когда разработчик БД не знает тонкостей алгоритмов работы приложения:
WITH ss
AS
(
SELECT s.* FROM gv$session s WHERE 0=0 AND s.machine LIKE 'prod-asr-servic%.serbao.fe'
)
SELECT t.* FROM gv$active_session_history t, ss WHERE 0=0 AND t.session_id = ss.sid
--AND t.sql_id IN ('1fab1xh4nb9xh','38319htpnu5q7')
--AND t.session_id IN ('307','64')
--AND to_date(t.sql_exec_start,'dd.mm.yyyy hh24:mi:ss') > to_date('04.08.2014 11:30:00','dd.mm.yyyy hh24:mi:ss')
ORDER BY t.sample_time DESC;

Запрос для извлечения кода SQL-запросов:
SELECT t.* FROM DBA_HIST_ACTIVE_SESS_HISTORY t
WHERE 0=0 AND t.sql_id LIKE '%status_id = (select s.status_id from dictstatus s where %';
SELECT t.* FROM DBA_HIST_ACTIVE_SESS_HISTORY t WHERE 0=0 AND t.sql_id IN ('bzz7bp7ju6pad');
SELECT t.* FROM gv$sqltext t WHERE 0=0 AND t.sql_id = 'bzz7bp7ju6pad' ORDER BY t.inst_id, t.piece;
SELECT t.* FROM gv$sqltext t WHERE 0=0 AND t.sql_text LIKE '%update contract%';
SELECT t.* FROM Dba_Hist_Sqltext t WHERE 0=0 AND t.sql_id IN ('bzz7bp7ju6pad');

Запрос выдаёт блокирующего и заблокированного пользователей:
SELECT /*+ rule */
s1.username blocker, s1.sid sid_blocker, s1.serial#, s1.MACHINE, s1.MODULE, s1.ACTION,
s2.username is_blocked, s2.sid sid_blocked, s2.serial#, s2.MACHINE, s2.MODULE, s2.ACTION,
s1.SQL_HASH_VALUE sql_blocker,
s2.SQL_HASH_VALUE sql_blocked
FROM v$lock a, v$lock b, v$session s1, v$session s2
WHERE a.id1 = b.id1 AND a.id2 = b.id2 AND b.request > 0
AND a.sid=s1.sid AND b.sid=s2.sid AND a.sid<>b.sid;

четверг, 23 июля 2015 г.

Тонкость в использовании DBMS_PARALLEL_EXECUTE.RUN_TASK

При использовании DBMS_PARALLEL_EXECUTE выяснилось, что DBMS_PARALLEL_EXECUTE.RUN_TASK не всегда запускает необходимое кол-во параллельных процессов.
Код запуска параллельных процессов:
DBMS_PARALLEL_EXECUTE.CREATE_CHUNKS_BY_SQL
( task_name   => 'TASK_PJOB',
sql_stmt    => 'SELECT level start_id, level end_id FROM dual connect by level <= '||v_count_string,
by_rowid    => FALSE
);

DBMS_PARALLEL_EXECUTE.RUN_TASK
( task_name      => 'TASK_PJOB',
sql_stmt       => 'BEGIN PKG_PJOB.P_PJOB(:start_id, :end_id); END;',
language_flag  => DBMS_SQL.NATIVE,
parallel_level => v_parallel_level
);
При использования данного примера, первоначально переменная v_count_string была равна v_parallel_level.
При реальной эксплуатации на 3-x нодовом кластере с 48 ядрами, в среднем запускалось в параллельном режиме 12-14 процессов из 20 плановых, остальные запускались по мере окончания работы запущенных при старте. Но такой вариант работы не подходит, т.к. получаем псевдо-параллельное выполнение задач.
При использовании процедуры DBMS_PARALLEL_EXECUTE.CREATE_CHUNKS_BY_ROWID данной проблемы не наблюдается, но она не всегда удобна в использовании.
В ходе тестирования выяснилось, что если  переменная v_parallel_level (100) больше v_count_string (20) в 5 раз, то всегда запускается 20 параллельных процессов.
Поэтому при использовании DBMS_PARALLEL_EXECUTE.CREATE_CHUNKS_BY_SQL об этом эффекте нужно помнить.
Проверялось на Oracle 11.2.0.4.0.

среда, 15 июля 2015 г.

Delete archive logs from a source DB

После запуска процесса репликации GoldenGate, обязательно возникнет инфраструктурная задача по очистке архивлогов на источнике.
Необходимо выполнить два пункта:
1. Согласно документации https://docs.oracle.com/cd/E11882_01/server.112/e17069/strms_adcapture.htm#i1010653 необходимо уменьшить значение параметра CHECKPOINT_RETENTION_TIME, т.к. значение по умолчанию слишком велико.
$ sqlplus '/ as sysdba'
sql> BEGIN
  DBMS_CAPTURE_ADM.ALTER_CAPTURE(
    capture_name              => 'OGG$CAP_EXTO',
    checkpoint_retention_time => );
END;
/
sql> select T.CHECKPOINT_RETENTION_TIME from DBA_CAPTURE t where capture_name = 'OGG$CAP_EXTO';
где EXTO - имя экстрактора.

2. Для уменьшения вероятности возникновения ошибок при работе rman
rman-08137: warning: archived log not deleted, needed for standby or upstream capture process
необходимо увеличить частоту обновления поля min_required_capture_change# представления v$database.

Данное поле обновляется раз в 6 часов, что очень много при нормальной работе экстракторов. Поэтому складывается ситуация когда значение поля required_checkpoint_scn представления dba_capture оказывается намного больше, и архивлоги обработанные экстрактором не могут быть удалены rman.
Согласно документации Doc ID 1581365.1 пункт Updates to V$DATABASE.MIN_REQUIRED_CAPTURE_CHANGE#
в param-файле экстрактора EXTO после строки USERID (DBLOGIN)
нужно выставить значение переменной _CKPT_RETENTION_CHECK_FREQ, например 3 часа:
TRANLOGOPTIONS INTEGRATEDPARAMS(_CKPT_RETENTION_CHECK_FREQ 10800)

После запуска экстрактора в представлениях переменных CAPTURE-процессов можно наблюдать значение _CKPT_RETENTION_CHECK_FREQ:
/* All Capture parameters */
select * from DBA_CAPTURE_PARAMETERS order by CAPTURE_NAME, PARAMETER;

/* Non-Default Capture parameters */
select * from DBA_CAPTURE_PARAMETERS where SET_BY_USER='YES' order by CAPTURE_NAME, PARAMETER;

Слишком часто V$DATABASE.MIN_REQUIRED_CAPTURE_CHANGE# обновлять не стоит, т.к. в момент обновления все процессы переходят в ожидание.

Update.
От последствий разворачивания Downstream-репликации Goldengate на источнике остался LOG_ARCHIVE_DEST_3 (в тестовых средах LOG_ARCHIVE_DEST может остаться от standby). 

3. Необходимо удостовериться, что на источнике отключены дополнительные/неактивные LOG_ARCHIVE_DEST
Для подобных LOG_ARCHIVE_DEST нужно выполнить команду:
$ sqlplus '/ as sysdba'
sql> ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_3='defer';
4. В случае, если отключение LOG_ARCHIVE_DEST не поможет в решение проблемы rman-08137: warning: archived log not deleted, needed for standby or upstream capture process, необходимо воспользоваться рекомендацией из Doc ID 1380368.1.
$ sqlplus '/ as sysdba'
sql> alter system set "_deferred_log_dest_is_valid" = FALSE scope=both;
Определение параметра _deferred_log_dest_is_valid: 
$ sqlplus '/ as sysdba'
sql> select ksppinm, ksppdesc  from x$ksppi where ksppinm = '_deferred_log_dest_is_valid'; 
KSPPINM                                  KSPPDESC 
----------------------------------      -------------------------------------------------------------------------------------- 
_deferred_log_dest_is_valid             consider deferred log dest as valid for log deletion (TRUE/FALSE) 

пятница, 3 июля 2015 г.

ASMCMD - курьезы

ASMCMD продолжает радовать необычными тонкостями. Например попыткой выйти из папки, которой уже нет.

ASMCMD [+data/rdbdevgg/archivelog/2015_04_30] > ls -l
Type        Redund  Striped  Time             Sys  Name
ARCHIVELOG  UNPROT  COARSE   APR 30 14:00:00  Y    thread_1_seq_22894.2939.878394477
ARCHIVELOG  UNPROT  COARSE   APR 30 14:00:00  Y    thread_1_seq_22895.4085.878394517
ARCHIVELOG  UNPROT  COARSE   APR 30 14:00:00  Y    thread_1_seq_22896.2938.878394563
ARCHIVELOG  UNPROT  COARSE   APR 30 14:00:00  Y    thread_1_seq_22897.3314.878394599
ASMCMD [+data/rdbdevgg/archivelog/2015_04_30] > rm thread_1_seq_22894.2939.878394477
....
ASMCMD [+data/rdbdevgg/archivelog/2015_04_30] > rm thread_1_seq_22897.3314.878394599
ASMCMD [+data/rdbdevgg/archivelog/2015_04_30] > ls -l
ASMCMD-8002: entry '2015_04_30' does not exist in directory '+data/rdbdevgg/archivelog/'
ASMCMD [+data/rdbdevgg/archivelog/2015_04_30] > cd ..
ASMCMD-8002: entry '2015_04_30' does not exist in directory '+data/rdbdevgg/archivelog/'
ASMCMD [+data/rdbdevgg/archivelog/2015_04_30] > pwd
+data/rdbdevgg/archivelog/2015_04_30
ASMCMD [+data/rdbdevgg/archivelog/2015_04_30] > cd +data/rdbdevgg/archivelog/

Вышел на уровень выше.


четверг, 2 июля 2015 г.

Копирование файлов между ASM инстансами

При работе с GoldenGate в режиме Downstream возникла необходимость в копировании archivelog между двумя инстансами ASM.
На source ASM нужно выполнить команду:
ASMCMD [+] >cp +DATA/arm4dev/ARCHIVELOG/2014_09_30/thread_1_seq_5689.451.859666035  sys@dev-rdb.+ASM:+data/DEV_RDB/archivelog/2014_09_30/thread_1_seq_5689.451
Где:
dev-rdb - host dest-сервера БД из файла /etc/hosts
+ASM - имя ASM-инстанса на dest-сервере БД
+data/DEV_RDB/archivelog/2014_09_30/thread_1_seq_5689.451 - путь и имя файла, суффикс incarnation необходимо стирать.

На dest ASM файлы копируются в каталог +DATA/ASM/ARCHIVELOG/
Т.е., если выполнить команду в каталоге с именем дня когда выполняется копирование:
ASMCMD [+data/dev_rdb/ARCHIVELOG/2014_10_03] > ls -ls
Type Redund Striped Time Sys Block_Size Blocks Bytes Space Name
ARCHIVELOG UNPROT COARSE OCT 03 11:00:00 Y 512 471565 241441280 243269632 none => thread_2_seq_8340.601.859982211
ARCHIVELOG UNPROT COARSE OCT 03 13:00:00 Y 512 353388 180934656 182452224 none => thread_2_seq_8347.577.859984811
N thread_2_seq_8348.521 => +DATA/ASM/ARCHIVELOG/thread_2_seq_8348.521.355.859988579
то можно увидеть ссылку на истинное положение файла.

Затем этот скопированный файл, можно зарегистрировать для экстрактора на dest БД:
SQL> alter database register or replace logical logfile '+DATA/ASM/ARCHIVELOG/thread_1_seq_5689.451.454.859914049' FOR 'OGG$CAP_XO'