SMON. Slow Rollback of Dead Transactions

Проблема: Имеется мёртвая(Dead) транзакция которая откатывается со скоростью 1-2 блока в секунду, которая блокирует выполнение update/delete/insert с ожиданием transaction(event#=1074, name=transaction). Версия Oracle: 19.21.

Т.к. откат транзакции может занять значительное время, самое время как то помочь этому процессу. Для этого, нужно дропнуть обьект, с которым связана транзакция из-за которого откат идёт очень медленно. Как определить объект который нужно дропунуть? Вот тут всё может быть не однозначно, т.к. в транзакции может быть замешано N таблиц. В моём случае я включил трассировку 10046 для процесса SMON, в которой были ожидания вида ‘enq: CR — block range reuse ckpt’ obj#=МойПроблемныйОбъект, далее я сдампил ещё заголовок undo сегмента(alter system dump undo header «_ИмяСегмента») и ундо блоки связанные с транзакцией (alter system dump undo block «_ИмяСегмента» XID номер_USN номер_SLT номер_SEQ).

Откуда, что берём:

USN, SLT,SEQ-  из select * from v$fast_start_transactions
_ИмяСегмента- из Select * from v$rollname where usn = USN

В дампе блоков связанных с транзакцией кучи вот такого:

KTSL - LOB Persistent Undo Block (PUB) undo record.

Есть подозрения, что KTSL это -Kernel Transaction Segment LOB, но это не точно. В дампе заголовка ундо и в дампе блоков связанных с транзакцией, должна быть связь в виде: в заголовке ундо сегмента в разделе TRN TBL, в колонке cmt есть значение 0, а в колонке dba на этом же уровне, имеются координаты блока, сдампив который, мы попадём в UBA, который связан с alter system dump undo block «_ИмяСегмента» XID номер_USN номер_SLT номер_SEQ.

Нужно взять книжку Oracle Core от Jonathan Lewis, и ещё раз перечитать....

Проанализировав кучу текста, выбираем нужный обьект и дропаем))):

alter system set "_smu_debug_mode"=1024;
oradebug setospid <ospid of SMON process> 
oradebug event 10513 trace name context forever, level 2
drop table owner.table purge;
purge recyclebin;
oradebug event 10513 trace name context off
alter system set "_smu_debug_mode"=0;

Так же, я использовал fast_start_parallel_rolback=false;(переключение этого параметра может остановить процесс отката, тут либо инстанс перезапускать, либо пытаться оживить SMON).

Откат транзакции ускорится в сотни раз. Как завершится, создаём таблицу по новой.

Полезные ноты:

Database Hangs Because SMON Is Taking 100% CPU Doing Transaction Recovery (Doc ID 414242.1)
IF: Transaction Recovery or Rollback of Dead Transactions (Doc ID 1951738.1)

Отдельно хочу отметить:

Bug 11790175 — SMON spins in rollback of LOB due to double allocated block like bug 11814891 (Doc ID 11790175.8)

Это древний баг, описание которого в моём случае совпадает только по двум критериям:

  1. Медленный откат
  2. Проблемный объект: LOB

UNDO и REDO, тяжелая тема… возможно есть метод и попроще.

ORA-00800: soft external error, arguments: [Set Priority Failed]. Dism(128). Oracle 19c

Коротенькая заметка про очередные грабли, всплывшие где-то с 19.16, но так-же существуют в плоть до 19.22.

Дано:

Oracle: 19.22

OS: Oracle Linux Server release 8.3

Kernel: 5.4.17-2011.7.4.el8uek.x86_64

При старте БД наблюдаем в алерт логе такую картину:

Starting background process VKTM
Errors in file /oracle/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_vktm_61290.trc  (incident=146927):
ORA-00800: soft external error, arguments: [Set Priority Failed], [VKTM], [Check traces and OS configuration], [Check Oracle document and MOS notes], []
Incident details in: /oracle/app/oracle/diag/rdbms/orcl/orcl/incident/incdir_146927/orcl_vktm_61290_i146927.trc
Error attempting to elevate VKTM's priority: no further priority changes will be attempted for this process


Starting background process LGWR
Errors in file /oracle/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_lgwr_61456.trc  (incident=147055):
ORA-00800: soft external error, arguments: [Set Priority Failed], [LGWR], [Check traces and OS configuration], [Check Oracle document and MOS notes], []
Incident details in: /oracle/app/oracle/diag/rdbms/orcl/orcl/incident/incdir_147055/orcl_lgwr_61456_i147055.trc

Starting background process DBW0
Errors in file /oracle/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_dbw0_61444.trc  (incident=147039):
ORA-00800: soft external error, arguments: [Set Priority Failed], [DBW0], [Check traces and OS configuration], [Check Oracle document and MOS notes], []
Incident details in: /oracle/app/oracle/diag/rdbms/orcl/orcl/incident/incdir_147039/orcl_dbw0_61444_i147039.trc

Просмотрев трейсы, находим много общего, а именно:

Error Info: Category(-2), Opname(skgdism_send), Loc(sp.c:setpr:0), ErrMsg(Operation not permitted) Dism(128)

Если пойти на MOS то можно найти ноту ORA-00800: soft external error, arguments: [Set Priority Failed], [VKTM] (Doc ID 2931494.1), которая, как по мне, ведёт в тупик(если конечно у вас на $ORACLE_HOME/bin/oradism установлены верные разрешения root:oinstall 4750), особенно если у вас 19.22.

Я же просто установил cgroup_disable=cpu в grub.

vi /etc/default/grub. Добавляем cgroup_disable=cpu в секцию  GRUB_CMDLINE_LINUX.

Далее выполнить:

Для легаси BIOS: grub2-mkconfig —output=/boot/grub2/grub.cfg

Для  UEFI: grub2-mkconfig —output=/boot/efi/EFI/redhat/grub.cfg.

[root@perfdbhost ~]# grub2-mkconfig --output=/boot/grub2/grub.cfg
Generating grub configuration file ...
device-mapper: reload ioctl on osprober-linux-nvme0n4p1 (252:2) failed: Device or resource busy
Command failed.
device-mapper: reload ioctl on osprober-linux-nvme0n5p1 (252:2) failed: Device or resource busy
Command failed.
Done

Перезагружаем хост.

P.S. В дальнейшем можно убрать cgroup_disable=cpu, процессы не получают(??) ошибок Set Priority Failed.

ORA-600 [6109] «Cannot get space to grow the ITL in an EMPTY block !!». Oracle 19

Из серии «никогда такого не было, и вот опять». Данная ошибка по сути является багом и её не должно быть. Первые упоминания о исправлении данной ошибки датируются версией 7.3.3(да, да, очень старая) и заканчиваются на отметке версии 10.1.0.2. Но как бы не так, данная ошибка воспроизводится(не всегда, но достаточно часто) в 19.3 и 19.19. Стоит отметить, что ошибка нашлась при синтетических тестах.

Для воспроизведения ошибки, нужно:

create table t1(
id varchar2(4000));
alter table t1 add constraint idpk primary key(id);
create sequence t1seq cache 5000;

Сам тест:

Запустить 5-10 конкурентных сессий, без использования PL/SQL, используя только sql:

next_val_seq_id_bind=t1seq.nextval||rpad(‘X’,3980,’R’)

insert into t1 values(:next_val_seq_id_bind);
commit;
delete from t1 where t1.id= :next_val_seq_id_bind;
commit;

Сам тест, является неким граничным/частным случаем, когда на один блок, приходится одна строка.

SR я завёл.

Беспричинный рост размера таблицы. Oracle 19.19, bug 30265523.

Дано: Oracle 19.19, RHEL8, размер блока 8к

После установки DBRU19.19 на 19.9, одна таблица стала линейно подрастать. Таблица буферная, в неё идёт вставка и практически стразу идёт удаление, в таблице постоянно находится порядка 1000 строк, но каждый день таблица прибавляет в объёме.  При поиске на oracle support был найдет Bug 30265523 — blocks are not marked as free in assm after delete — 12.2 and later (Doc ID 30265523.8) .

Выполнив дамп блока первого уровня битовой карты свободного места в экстете(first level bitmap block) вижу вот такую картину:

  --------------------------------------------------------

  DBA Ranges :

  --------------------------------------------------------

   0x04000080  Length: 64     Offset: 0     

  

   0:Metadata   1:Metadata   2:FULL   3:FULL
   4:FULL   5:FULL   6:FULL   7:FULL
   8:FULL   9:FULL   10:FULL   11:FULL
   12:FULL   13:FULL   14:FULL   15:FULL
   16:FULL   17:FULL   18:FULL   19:FULL
   20:FULL   21:FULL   22:FULL   23:FULL
   24:FULL   25:FULL   26:FULL   27:FULL
   28:FULL   29:FULL   30:FULL   31:FULL
   32:FULL   33:FULL   34:FULL   35:FULL
   36:FULL   37:FULL   38:FULL   39:FULL
   40:FULL   41:FULL   42:FULL   43:FULL
   44:FULL   45:FULL   46:FULL   47:FULL
   48:FULL   49:FULL   50:FULL   51:FULL
   52:FULL   53:FULL   54:FULL   55:FULL
   56:FULL   57:FULL   58:FULL   59:FULL
   60:FULL   61:FULL   62:FULL   63:FULL

  --------------------------------------------------------
  ktspfsc -
  nro:62 ncmp:0 nff:62 nxo:1 lastxs:30 nxid:1 ff:30
  clntime: 1689652737 addtime:0 spare1:0 spare2:0
  ro: rejection opcode, xo: xid offset List
  0. ro:0 xo:-1  1. ro:0 xo:-1  2. ro:3 xo:-1  3. ro:3 xo:-1
  4. ro:3 xo:-1  5. ro:3 xo:-1  6. ro:3 xo:-1  7. ro:3 xo:-1
  8. ro:3 xo:-1  9. ro:3 xo:-1  10. ro:3 xo:-1  11. ro:3 xo:-1
  12. ro:3 xo:-1  13. ro:3 xo:-1  14. ro:3 xo:-1  15. ro:3 xo:-1
  16. ro:3 xo:-1  17. ro:3 xo:-1  18. ro:3 xo:-1  19. ro:3 xo:-1
  20. ro:3 xo:-1  21. ro:3 xo:-1  22. ro:3 xo:-1  23. ro:3 xo:-1
  24. ro:3 xo:-1  25. ro:3 xo:-1  26. ro:3 xo:-1  27. ro:3 xo:-1
  28. ro:3 xo:-1  29. ro:3 xo:-1  30. ro:3 xo:-1  31. ro:3 xo:-1
  32. ro:3 xo:-1  33. ro:3 xo:-1  34. ro:3 xo:-1  35. ro:3 xo:-1
  36. ro:3 xo:-1  37. ro:3 xo:-1  38. ro:3 xo:-1  39. ro:3 xo:-1
  40. ro:3 xo:30  41. ro:3 xo:-1  42. ro:3 xo:-1  43. ro:3 xo:-1
  44. ro:3 xo:-1  45. ro:3 xo:-1  46. ro:3 xo:-1  47. ro:3 xo:-1
  48. ro:3 xo:-1  49. ro:3 xo:-1  50. ro:3 xo:-1  51. ro:3 xo:-1
  52. ro:3 xo:-1  53. ro:3 xo:-1  54. ro:3 xo:-1  55. ro:3 xo:-1
  56. ro:3 xo:-1  57. ro:3 xo:-1  58. ro:3 xo:-1  59. ro:3 xo:-1
  60. ro:3 xo:-1  61. ro:3 xo:-1  62. ro:3 xo:-1  63. ro:3 xo:-1

Наблюдаем rejectioncode 3, ну и все блоки FULL. Что полностью совпадает с описанием бага, который как бы исправлен. Если сделать дамп блока с данными, то в нём будет всего одна строка, которая имеет пометку, что она удалена(—HDFL—). Стоит отметить, что проблемная таблица имеет несколько полей varchar2(4000), из которых под завязку заполняется всегда 2 поля, а иногда 3 поля, остальные поля всегда null, связанных и смигированных(chained and migrated rows) строк таблица не имеет.

Дальнейшие эксперименты показали, что:

  1. Не помогает или делает хуже _enable_rejection_cache = false
  2. Не помогает _assm_segment_repair_bg=false
  3. Комбинация _enable_rejection_cache = false и _fix_control=’32075777:ON’, не помогает.
  4. Потенциальным решением(костылём) может является только установка одного параметра _fix_control=’32075777:ON’.

Выставив _fix_control=’32075777:ON’,  можно удержать таблицу в нормальных рамках размера. При постоянной нагрузке, таблица остановила свой рост. При одинаковой нагрузке, в 19.9 таблица имелеа размер в пару сотен мегабайт, в 19.19 с _fix_control=’32075777:ON’, рост остановился на отметке в 1Гб. Также при установки _fix_control=’32075777:ON’, появилась не нулевая метрика ASSM_bg_slave_fix_state, которая по видимому увеличивается после того, как фиксится статус блоков в битовой карте, и стала заполнятся x$ktsp_repair_list(я так понимаю, здесь отображён список сегментов, по которым сработал механизм починки сегмента). SR я завёл.

Ну и в целом, как изменилась работа ASSM. До 06/21 бд работала на DBRU 19.9, после 6/20 на 19.19:

If the rman restore process has stopped due to an error, how can you continue the restore from the point of interruption without starting from the beginning?

This note is aimed at saving time on manual calculation of missing files that need to be restored and avoiding the need to restart the restore process from scratch.

The scenario involves initiating a database restore using RMAN (RESTORE DATABASE), and after some time, encountering an error:

RMAN-00571: ===========================================================

RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============

RMAN-00571: ===========================================================

ORA-19870: error while restoring backup piece 856802_vg1qa4qf_1_1

ORA-19504: failed to create file "+DATA"

ORA-17502: ksfdcre:4 Failed to create file +DATA

ORA-15041: diskgroup "DATA" space exhausted

And basically… after resolving the ORA-15041 issue, we have two options: either start the restore process from scratch (over 40TB), or manually determine what has already been restored (around 1800 files) and only recover the necessary ones (~120 files), constructing a new RMAN script based on the information mentioned above.

However, there is a script available that can be used:

Option 1:

select q'!set newname for DATAFILE !'||datafiled||q'! to '+ASMDG';!' from (
select 
dcopy.file# fcopy,d.file# datafiled 
from 
(
select file# from v$datafile_copy c where c.name is not null
order by c.file#) dcopy right join v$datafile d on dcopy.file#=d.file#)
where fcopy is null
union all
select q'!restore datafile !'||dfiled||q'!;!' from (select 
dcopy.file# fcopy,d.file# dfiled 
from 
(
select file# from v$datafile_copy c where c.name is not null
order by c.file#) dcopy right join v$datafile d on dcopy.file#=d.file#)
where fcopy is null

Option 2(In the last line of the output result, you need to replace the comma with a semicolon):

select q'!set newname for DATAFILE !'||datafiled||q'! to '+ASMDG';!' from (
select 
dcopy.file# fcopy,d.file# datafiled 
from 
(
select file# from v$datafile c where c.bytes=0 
order by c.file#) dcopy left join v$datafile d on dcopy.file#=d.file#)
union all
select q'!restore datafile !' from dual
union all
select dfiled||q'!,!' from (select 
dcopy.file# fcopy,d.file# dfiled 
from 
(
select file# from v$datafile c where c.bytes=0
order by c.file#) dcopy left join v$datafile d on dcopy.file#=d.file#)

Both scripts generate «set newname for DATAFILE» and «restore datafile» commands for each data file that needs to be restored. We wrap the script’s output in a «run» block and execute it. After all the files are restored, we perform a «switch database to copy» and continue with the recovery process.

However, it should be noted that under certain circumstances, the script may not work correctly(Especially option 1). For example, on a normally functioning database in open mode, the script’s output may not match reality because there may be no entries in v$datafile_copy, or conversely, there may be many entries in v$datafile_copy, and both scenarios are normal.

Therefore, to avoid causing any issues with the database, please proceed with caution.

Если rman restore остановился по причине какой-то ошибки, как продолжить восстановление с места остановки, не начиная всё сначала?

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

Сценарий, запускаем восстановление бд через rman(restore database) и, через какое-то время получаем ошибку:

RMAN-00571: ===========================================================

RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============

RMAN-00571: ===========================================================

ORA-19870: error while restoring backup piece 856802_vg1qa4qf_1_1

ORA-19504: failed to create file "+DATA"

ORA-17502: ksfdcre:4 Failed to create file +DATA

ORA-15041: diskgroup "DATA" space exhausted

И как бы всё… решив проблему с ORA-15041, нужно либо начинать рестор по новой(овер 40ТБ), либо вычислять вручную или ещё как-то, что было восстановлено(~1800 файлов) и долить только нужное(~120 файлов), сконструировав на вышеизложенное новый rman скрипт.

Но можно воспользоваться скриптами:

Вариант 1:

select q'!set newname for DATAFILE !'||datafiled||q'! to '+ASMDG';!' from (
select 
dcopy.file# fcopy,d.file# datafiled 
from 
(
select file# from v$datafile_copy c where c.name is not null
order by c.file#) dcopy right join v$datafile d on dcopy.file#=d.file#)
where fcopy is null
union all
select q'!restore datafile !'||dfiled||q'!;!' from (select 
dcopy.file# fcopy,d.file# dfiled 
from 
(
select file# from v$datafile_copy c where c.name is not null
order by c.file#) dcopy right join v$datafile d on dcopy.file#=d.file#)
where fcopy is null

Вариант 2(в последней строчке вывода результата, нужно заменить запятую на точку с запятой):

select q'!set newname for DATAFILE !'||datafiled||q'! to '+ASMDG';!' from (
select 
dcopy.file# fcopy,d.file# datafiled 
from 
(
select file# from v$datafile c where c.bytes=0 
order by c.file#) dcopy left join v$datafile d on dcopy.file#=d.file#)
union all
select q'!restore datafile !' from dual
union all
select dfiled||q'!,!' from (select 
dcopy.file# fcopy,d.file# dfiled 
from 
(
select file# from v$datafile c where c.bytes=0
order by c.file#) dcopy left join v$datafile d on dcopy.file#=d.file#)

Оба скрипта формируют “set newname for DATAFILE” и “ restore datafile” для каждого файла данных, который нужно восстановить. Оборачиваем вывод скрипта в run блок и запускаем, после того как все файлы восстановлены(restore), выполняем switch database to copy, и продолжаем recover.

Следует, однако, заметить, что, при определённых обстоятельствах, скрипт(особенно вариант 1) будет работать не верно, например на нормально работающей бд в режиме open, вывод скрипта не будет совпадать с реальностью, т.к. в v$datafile_copy может не быть записей, а может быть и наоборот (много записей в v$datafile_copy) и это нормально.

Поэтому, дабы не завалить бд, будьте аккуратны. 

Log file sync switching to post/wait. eng.

DB version: Oracle 19.9 x86.

In this note, I will visually demonstrate how the transition of lgwr from poll->post to post/wait mode can look like.

Investigate time when it happened by using trace file of lgwr process:

*** 2023-02-16T12:45:09.010167+06:00 
Log file sync switching to post/wait 
Current approximate redo synch write rate is 10286 per sec
Fig.1
Fig.2

Figure 1 shows that the transition of lgwr from poll->post to post/wait mode led to a doubling of the log file sync wait time, from 250 microseconds to 500 microseconds.
Additionally, the number of redo blocks written in 128KB doubled. Although not visible in the graphs, there is also a decrease in the number of redo blocks written that are much smaller than 128KB (4, 8, 16, 32KB, etc).

Figure 2 shows how the number of log file parallel write waits (oracledb_event_p3_log_file_parallel_write_p2) has changed.
The number of waits has decreased by half, but the duration of a single log file parallel write wait (oracledb_event_p2_log_file_parallel_write_p2) has increased by an average of 50%, from 50 microseconds to 75 microseconds.

It looks like some sort of ferry mode where fewer operations are performed with larger block sizes, resulting in a 2x reduction in response time. This behavior is subject to change according to the algorithm and database parameters associated with the adaptive operation of LGWR.

You can read more here:

  1. Adaptive Switching Between Log Write Methods can Cause ‘log file sync’ Waits (Doc ID 1462942.1)
  2. ADAPTIVE LOG FILE SYNC: ORACLE, PLEASE DON’T DO THAT AGAIN

Actually, the solution is: ALTER SYSTEM SET «_use_adaptive_log_file_sync» = FALSE;

Log file sync switching to post/wait

Версия: Oracle 19.9

В данной заметке показано наглядно, как может выглядеть переход lgwr от poll->post к режиму post/wait.

Смотрим в трейс файл процесса lgwr, находим там:

*** 2023-02-16T12:45:09.010167+06:00

Log file sync switching to post/wait

Current approximate redo synch write rate is 10286 per sec

Идём в графану и смотрим визуализацию этого события:

Рис1.

Рис2.

На рисунке 1 показано, что переход lgwr от poll->post к режиму post/wait привёл к увеличению ожидания log file sync в 2 раза, с 250мксек до 500мксек, также, увеличилось количество записи редо блоком в 128KB в два раза. На графики этого не видно, но также имеется снижение количества записи редо блоком гораздо меньшим чем 128KB(4,8,16,32KB etc).

На рисунке 2 показано, как изменилось количество ожиданий log file parallel write(oracledb_event_p3_log_file_parallel_write_p2). Количество ожиданий уменьшилось в два раза, в тоже время длительность одного ожидания log file parallel write(oracledb_event_p2_log_file_parallel_write_p2) увеличилось, в среднем на 50%, с 50мксек до 75мксек.

Выглядит как какой-то челночный режим, выполнить меньше операций большим размером блока, что даёт снижение отклика в 2 раза. Данное поведение меняется согласно алгоритму и параметрам базы данных связанных с адаптивной работы LGWR.

Подробнее можно почитать тут:

  1. Adaptive Switching Between Log Write Methods can Cause ‘log file sync’ Waits (Doc ID 1462942.1)
  2. ADAPTIVE LOG FILE SYNC: ORACLE, PLEASE DON’T DO THAT AGAIN

Собственно, решение такое: ALTER SYSTEM SET «_use_adaptive_log_file_sync» = FALSE;

Оптимизация работы rman catalog.

В больших база данных, размеры которых идут на десятки, а то и сотни ТБ, и в зависимости от политики резервного копирования, могут образоваться сотни тысяч backup piece. При таком количестве backup piece задачи по удалению из rman каталога старых бэкапов, особенно инициированные не в ручную, а выполняемые по регламенту из какого либо софта MML , могут не успеть за отведённое время удалить необходимый перечень записей из контрольного файла и rman catalog. Это приведёт к накоплению устаревших записей о бэкапах как в контрольном файле, так и в rman каталоге.

Создание данных индексов позволят ускорить удаление записей из rman каталога в 4 раза:

create index BDF_DBINC_KEY_IX1 on BDF(Dbinc_Key,CKP_SCN) 
create index BRL_DBINC_KEY_IX1 on BRL(Dbinc_Key,Low_Scn)
create index CDF_DBINC_KEY_IX1 on CDF(Dbinc_Key,Ckp_Scn)
create index ROUT_KEY_IX1 on ROUT(DB_KEY,Site_Key,Rout_Skey)
create index bp_ix1 on bp(DB_KEY,handle);

Так же, если в бд, откуда делаются бэкапы, при выполнении задач по удалению старых записей о бэкапах, присутствует ожидание  “recovery area: computing obsolete files”, то вам следует выполнить/проверить реакцию бд на  ALTER SYSTEM SET db_recovery_file_dest=» SCOPE=BOTH;  Если конечно, оно, db_recovery_file_dest, вам ненужно.

ORA-02376: invalid or redundant resource

If you have made export using FULL=y CONTENT=metadata_only from 19.3 db version, it is unable to import dump in 19.9 the cause of an error is ORA-02376: invalid or redundant resource.

If you search ORA-02376 on MOS you can find «DataPump Import Fails With Duplicated Resources In The Create Profile Statement (Doc ID 557383.1)», but this is not our case. The root of the problem is user profile which has PASSWORD_ROLLOVER_TIME option introduced from 19.12 according to Gradual Database Password Rollover. Creating profile with PASSWORD_ROLLOVER_TIME option produces an error ORA-02376 on db version lower than 19.12. I tested only 19.9. Export from 19.12 version and higher with parameter version=19.9, or 19.0, or 12.0 didn’t help.

You must skip profile from export and make it manually.