ORA-01403
ORA-01403: данные не найдены
Причина:
Вы пытались выполнить одно из следующих действий:
Вы выполнили SELECT INTO и строки не были возвращены.
Вы ссылались на неинициализированную строку в таблице.
Действие:
Прекратите обработку для данного оператора SELECT.
Время на прочтение
17 мин
Количество просмотров 4.9K
Предисловие
Убедительная просьба, рассматривать данный текст только как продолжение к статье о «Событийной модели логирования». Эта статья будет полезна тем, у кого уже реализовано логирование событий в БД и кто хотел бы осуществлять сбор статистики и начать проводить аналитику этих событий. Только представьте, что ваша БД сможет информировать вас о критичных сбоях системы, накапливать информацию о событиях в БД (кол-во повторений, период повторений и т.д.). И всё это без использования стороннего ПО силами одного PL/SQL.
Введение
В этом цикле статей будет показано как реализованный функционал «логирования» позволяет фиксировать факт возникновения не только ошибок (сообщение с типом «Error»), но и сообщений с предупреждением (тип «Warning»), информативных сообщений (с типом «Info») и т.д., поэтому, в рамках данных статей введём термин — «Модель логирования событий» (далее по тексту — «модель») или коротко «Логирование событий», где под «событием» подразумевается некоторое ожидаемое действие, возникшее в ходе штатной/внештатной работы алгоритма.
Модель логирования позволяет реализовать:
-
Единый подход в обработке и хранении событий (статья)
-
Собственную нумерацию и идентификацию событий происходящих в БД
-
Единый мониторинг событий (статья в разработке)
-
Анализ событий происходящих в БД (статья в разработке)
Описанные выше характеристики указаны в порядке нумерации и каждый следующий пункт (шаг) есть улучшение и усложнение существующей модели. Описание этой модели будет сложно выполнить в рамках одной статьи, поэтому опишем их последовательно. В этой (второй) статье создадим собственную нумерацию кодов для событий, а также создадим функционал идентификации событий происходящих в БД.
Для чего это нужно?
Для начала давайте рассмотрим пример. Вы реализовали логирование ошибок в вашей БД. С течением времени в ваш лог «прилетают» самые разнообразные ошибки. Предположим, имеются две ошибки вида «no_data_found» возникшие в двух разных процедурах при двух разных запросах (select). Первая ошибка возникла при попытке найти «email» клиента, что в принципе не является критичной ошибкой. Вторая ошибка возникла при попытке найти номер лицевого счета клиента, что вполне может являться критичной ошибкой. При этом если мы посмотрим в таблицу лога (из статьи), то увидим, что указанные ошибки будут храниться с одинаковым кодом 1403 (ORA-01403) в столбце msgcode. Более того, текст указанных ошибок будет практически аналогичным (текст полученный с помощью функции SQLERRM) за исключением имен объектов, на которых произошла ошибка. Для того чтобы понять является ли критичной конкретная ошибка, разработчику необходимо вникать в текст ошибки, смотреть в каком объекте возникла ошибка и на основе этой информации сделать вывод о срочности исправления. При этом, если мы сможем задать более четкое описание ошибки отличное от текста Oracle (SQLERRM), то это позволит упростить понимание причин возникновения и способов решения ошибки.
Ошибка |
Как сейчас |
Как должно быть (в идеале) |
Не найдена запись в таблице содержащей адреса электронной почты клиентов |
ORA-01403: данные не найдены |
USR0001: Не найден адрес электронной почты клиента id = *** (идентификатор клиента) |
Не найдена запись в таблице содержащей лицевые счета клиентов |
ORA-01403: данные не найдены |
USR0002: Не найден лицевой счет клиента id = *** (идентификатор клиента) |
Из этого примера видно, что одна и та же ошибка «no_data_found» (ORA-01403: данные не найдены) может иметь совершенно разное значение с точки зрения бизнес логики, а значит нам необходимо разработать механизм, который позволит идентифицировать каждое событие происходящее в БД как отдельное событие с нашим внутренним уникальным кодом и текстом события (отличную от Oracle). Таким образом мы решаем две проблемы:
1) В месте возникновения ошибки мы устанавливаем уникальный код ошибки. В будущем это позволяет достаточно быстро найти место возникновения ошибки. Также, наличие уникальных кодов позволяет нам произвести точечный подсчет повторений и на основании этой информации принять решение об устранении данной ошибки.
2) Дополнительный «читаемый» текст позволяет сильно упростить понимание ошибки. В таблице выше показано, как одна и та же ошибка может запутать или разъяснить пользователю сведения об ошибке.
Надеюсь мне удалось объяснить зачем необходимо кодировать события в таблице логов. Далее по тексту, будут введены термины «Архитектурный лог» и «Пользовательский лог». На примере процедуры поиска активного номера телефона клиента будет показано как и зачем создано разделение на архитектурный и пользовательский лог.
Архитектурное логирование событий
Давайте рассмотрим пример, имеется процедура поиска активного номера телефона принадлежащего конкретному клиенту (для примера его id = 43). Предположим, что при постановке задачи для разработчика не было описания каких-либо особых условий т.е. по условиям задачи предполагалось, что для конкретного пользователя (id = 43, идентификатор передается в качестве параметра) в таблице client_telnumbers всегда будет хотя бы одна запись с номером телефона клиента и признаком «активный» (значение поля enddate равно дате 31.12.5999 23:59:59, что означает что номер используется клиентом. В случае, любой другой даты в указанном поле означает, что номер перестал быть активным и более не используется), поэтому наша процедура будет выглядеть примерно так:
Исходный код демонстрационной процедуры
procedure p_get_telnumber(p_userid in number,
p_telnumber out number,
p_errcode out number,
p_errtext out varchar2)
is
v_objname varchar2(60) := utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(1));
v_telnumber client_telnumbers.telnumber%type;
begin
select telnumber
into v_telnumber
from client_telnumbers
where id = p_userid
and enddate = to_date('31.12.5999 23:59:59', 'dd.mm.yyyy hh24:mi:ss');
p_telnumber := v_telnumber;
p_errcode := 1;
exception
when others then
pkg_msglog.p_log_err(p_objname => v_objname,
p_msgcode => SQLCODE,
p_msgtext => SQLERRM,
p_paramvalue => 'p_userid = '||p_userid,
p_backtrace => dbms_utility.format_error_backtrace);
raise;
end p_get_telnumber;
Важно! Представленный код является примерным (примитивным) и служит только для демонстрации логирования в рамках данной статьи. В своих статьях я не выкладываю текст кода из реально действующих БД. Надеюсь, вы понимаете, что в реальности указанная процедура написана гораздо сложнее.
*Исходный код других используемых объектов смотрите в Git
Если мы будем использовать логирование ошибок как показано в предыдущей статье, то с течением времени обнаружим, что идентифицировать ошибки из данной процедуры будет сложно. Поэтому для всех ошибок попадающих в обработку исключения «WHEN OTHERS» реализована процедура pkg_msglog.p_log_archerr, которая при первом возникновении ошибки автоматически присваивает ей уникальный код и сохраняет ошибку в таблице лога. В дальнейшем, при повторении данной ошибки процедура найдет ранее созданный код и использует его при логировании в таблице лога.
В итоге, после добавления блока «архитектурного» логирования (строки с 18 по 24), наша процедура будет выглядеть следующим образом:
Исходный код демонстрационной процедуры
procedure p_get_telnumber(p_userid in number,
p_telnumber out number,
p_errcode out number,
p_errtext out varchar2)
is
v_objname varchar2(60) := utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(1));
v_telnumber client_telnumbers.telnumber%type;
begin
select telnumber
into v_telnumber
from client_telnumbers
where id = p_userid
and enddate = to_date('31.12.5999 23:59:59', 'dd.mm.yyyy hh24:mi:ss');
p_telnumber := v_telnumber;
p_errcode := 1;
exception
-- Архитектурное логирование
when others then
pkg_msglog.p_log_archerr(p_objname => v_objname,
p_msgcode => SQLCODE,
p_msgtext => SQLERRM,
p_paramvalue => 'p_userid = '||to_char(p_userid),
p_backtrace => dbms_utility.format_error_backtrace);
raise;
end p_get_telnumber;
*Исходный код других используемых объектов смотрите в Git
На этапе написания текста процедуры разработчик не всегда может предугадать возникновение той или иной ошибки (если честно, не всегда есть на это время), поэтому на начальном этапе ему достаточно «отлавливать» абсолютно все ошибки возникающие в данной процедуре с помощью оператора «WHEN OTHERS». Таким образом мы можем ввести новый термин (в рамках данного цикла статей), «Архитектурные логирование» — это логирование всех ошибок, возникновение которых не предполагается при штатной работе алгоритма. Для функционала «Архитектурных ошибок» были созданы объекты: отдельный справочник ошибок messagecodes_arch и процедура pkg_msglog.p_log_archerr создания записи в таблице лога для указанного типа ошибок.
Исходный код таблицы
create table messagecodes_arch(objectname varchar2(120) not null,
sqlerrcode number not null,
msgcode varchar2(10) not null,
insertdate date default sysdate,
constraint pk_msgcode_arch_id primary key (objectname,sqlerrcode));
Ограничение в таблице на комбинацию (Имя объекта, код ошибки SQLCODE). При первом появлении ошибки создается запись в таблице и генерируется код ошибки «SYS0000» + счетчик ошибок. При повторном появлении указанной ошибки будет взят уже сгенерированный ранее код ошибки.
*Исходный код других используемых объектов смотрите в Git
Обратите внимание, что при использовании описанной модели «архитектурного» логирования у вас появляется функционал позволяющий максимально быстро реагировать на первое появление ошибки (в конкретной функции/процедуре). Для этого необходимо реализовать отдельный мониторинг архитектурных ошибок, который постараюсь продемонстрировать в следующей (третьей) статье. Использование процедуры pkg_msglog.p_log_archerr не требует каких-либо действий кроме описания входных параметров.
Таким образом мы можем создать базовый шаблон процедуры (функции), использование которого позволит вам гарантированно отлавливать все архитектурные ошибки в вашем коде.
Шаблон процедуры/функции с архитектурным логированием
-- Шаблон процедуры/функции для построения Событийной модели логирования
-- Обратите внимание, что каждый блок "begin ... end" содержит исключение вида "when others",
-- который осуществляет логирование Архитектурных ошибок.
-- Все остальные исключения вида "no_data_found", "too_many_rows" и др.
-- будут осуществлять логирование Пользовательских ошибок
procedure p_procedure_name(p_param1 in number,
p_param2 in varchar2,
p_param3 in date,
/* others param */
p_errcode out number,
p_errtext out varchar2)
is
v_objname varchar2(60) := utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(1));
/* variable */
v_msgcode messagelog.msgcode%type;
v_msgtext messagelog.msgtext%type;
begin
/* code */
begin
/* code */
exception
-- Пользовательское логирование
when no_data_found then
v_msgcode := 'USR0000'; -- внутренний код
v_msgtext := pkg_msglog.f_get_errcode(v_msgcode);
pkg_msglog.p_log_wrn(p_objname => v_objname,
p_msgcode => v_msgcode,
p_msgtext => v_msgtext,
p_paramvalue => 'p_param1 = '||to_char(p_param1)
||', p_param2 = '||p_param2
||', p_param3 = '||to_char(p_param3,'dd.mm.yyyy hh24:mi:ss'));
p_errcode := -1;
p_errtext := v_msgtext;
end;
/* code */
/* result */
p_errcode := 1;
exception
-- Пользовательское логирование
when no_data_found or too_many_rows then
v_msgcode := 'USR0000'; -- внутренний код
v_msgtext := pkg_msglog.f_get_errcode(v_msgcode);
pkg_msglog.p_log_wrn(p_objname => v_objname,
p_msgcode => v_msgcode,
p_msgtext => v_msgtext,
p_paramvalue => 'p_param1 = '||to_char(p_param1)
||', p_param2 = '||p_param2
||', p_param3 = '||to_char(p_param3,'dd.mm.yyyy hh24:mi:ss'));
p_errcode := -1;
p_errtext := v_msgtext;
-- Архитектурное логирование
when others then
pkg_msglog.p_log_archerr(p_objname => v_objname,
p_msgcode => SQLCODE,
p_msgtext => SQLERRM,
p_paramvalue => 'p_param1 = '||to_char(p_param1)
||', p_param2 = '||p_param2
||', p_param3 = '||to_char(p_param3,'dd.mm.yyyy hh24:mi:ss'),
p_backtrace => dbms_utility.format_error_backtrace);
raise;
end p_procedure_name;
Рекомендую использовать данный шаблон для построения «Событийной модели логирования».
*Исходный код других используемых объектов смотрите в Git
В рамках событийной модели логирования, предполагается, что все архитектурные ошибки будут исправляться отдельной задачей т.е. основная цель это устранить повторное появление ошибок с кодом «SYS****» в таблице лога. В указанной задаче вам необходимо либо устранить причины возникновения данной ошибки, либо добавить отдельную обработку ошибки отличную от «when others», которую в дальнейшем будем назвать «пользовательское» логирование (в рамках данного цикла статей).
Пользовательское логирование событий
Предположим, что однажды в нашей процедуре get_telnumber произошла «архитектурная ошибка». В частности, для конкретного пользователя в таблице client_telnumbers хранится два номера телефона с признаком «активный». В таком случае, процедура «упадёт» с ошибкой «ORA-01422: too_many_rows». При этом, наш функционал архитектурного логирования сгенерировал новый код ошибки «SYS0061» и создал запись в таблице лога.
Самое важно в такой ситуации это не откладывать «на потом» исправление архитектурных ошибок. В идеале, необходимо создать отдельную задачу (баг) и в рамках неё устранить ошибку.
Предположим ,что была создана отдельная задача для устранения ошибки и назначена разработчику. В рамках этой задачи, разработчик совместно с технологом, аналитиком и др. коллегами пришел к выводу, что указанная ошибка носит систематический характер, является некорректной работой системы и требует исправления. В качестве мер исправления было решено добавить обработку события «too_many_rows» с последующим логированием события в таблице лога и выводом текста ошибки для пользователя.
Для этого в процедуре get_telnumber добавлено исключение (exception) «too_many_rows» пользовательского логирования. Также, был создан справочник пользовательских ошибок отличный от архитектурного справочника, тем что в него все записи добавляются разработчиком «вручную». Наверное это самое слабое место во всей архитектуре логирования. Предполагается, что разработчик должен описать исключение (exception) и создать для него уникальный код ошибки. Также, желательно к указанной ошибке сформулировать читаемый текст ошибки (для своих коллег, пользователя, техподдержки и т.д.), что бывает иногда очень сложным (из личного опыта).
Таблица пользовательских ошибок и процедура их «регистрации» будет выглядеть следующим образом:
Исходный код таблицы пользовательских ошибок и процедуры регистрации
create table messagecodes(msgcode varchar2(10) not null,
rustext varchar2(500) not null,
msgpriority number(1) default 1,
insertdate date default sysdate,
lastupdate date default null,
constraint pk_messagecodes_id primary key (msgcode));
Регистрация пользовательских ошибок производится процедурой p_insert_msgcode. На вход подается код и текст ошибки. В случае, если по указанному коду нет записей в справочнике messagecodes, то создается новая запись (производится регистрация). В случае, если по коду ошибки найдена запись, то производится сравнение текстов ошибки, в случае расхождений производится обновление текста, иначе работа процедуры завершается без изменений. Таким образом мы всегда можем корректировать текст ошибок.
-- Пример регистации пользовательских ошибок
begin
pkg_msglog.p_insert_msgcode('USR0001','Не найден адрес электронной почты клиента id = $1!',1);
pkg_msglog.p_insert_msgcode('USR0002','Не найден лицевой счет клиента id = $1!',5);
pkg_msglog.p_insert_msgcode('USR0003','Для клиента id = $1 найдено два и более активных номеров телефона!',1);
pkg_msglog.p_insert_msgcode('USR0004','Номер мобильного телефона не соответствует маске (clientid = $2)',1);
commit;
end;
Обратите внимание, что текст ошибок имеет параметризацию т.е. для ошибки в тексте имеются специальные символы $1, $2, $3 и т.д. Например, рассмотрим ошибку «USR0003» с текстом «Для клиента id = $1 найдено два и более активных номеров телефона!» при вызове функции f_get_errcode на вход подаётся код ошибки и параметры ошибки. Далее, функция по коду ошибки найдет строку, в тексте ошибки заменит подстроку «$1» на значение параметра to_char(p_userid) т.е. подставит значение to_char(p_userid).
v_msgcode := 'USR0003'; -- внутренний код
v_msgtext := pkg_msglog.f_get_errcode(p_msgcode => v_msgcode,
p_msgparam => to_char(p_userid));
В случае если в тексте ошибки будут два и более спецсимвола $1, $2, $3 и т.д., то параметры передаются с использованием символа-разделителя «;».
Итого, содержимое справочника пользовательских ошибок будет выглядеть следующим образом:
*Исходный код других используемых объектов смотрите в Git
После того, как мы «зарегистрировали» пользовательскую ошибку «USR0003» и добавив отдельную обработку пользовательского логирования (строки с 19 по 28), наша процедура get_telnumber будет выглядеть следующим образом:
Исходный код демонстрационной процедуры
procedure p_get_telnumber(p_userid in number,
p_telnumber out number,
p_errcode out number,
p_errtext out varchar2)
is
v_objname varchar2(60) := utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(1));
v_telnumber client_telnumbers.telnumber%type;
v_msgcode messagelog.msgcode%type;
v_msgtext messagelog.msgtext%type;
begin
select telnumber
into v_telnumber
from client_telnumbers
where id = p_userid
and enddate = to_date('31.12.5999 23:59:59', 'dd.mm.yyyy hh24:mi:ss');
p_telnumber := v_telnumber;
p_errcode := 1;
exception
-- Пользовательское логирование
when too_many_rows then
v_msgcode := 'USR0003'; -- внутренний код
v_msgtext := pkg_msglog.f_get_errcode(v_msgcode,to_char(p_userid));
pkg_msglog.p_log_wrn(p_objname => v_objname,
p_msgcode => v_msgcode,
p_msgtext => v_msgtext,
p_paramvalue => 'p_userid = '||to_char(p_userid));
p_errcode := -1;
p_errtext := v_msgtext;
-- Архитектурное логирование
when others then
pkg_msglog.p_log_archerr(p_objname => v_objname,
p_msgcode => SQLCODE,
p_msgtext => SQLERRM,
p_paramvalue => 'p_userid = '||to_char(p_userid),
p_backtrace => dbms_utility.format_error_backtrace);
raise;
end p_get_telnumber;
*Исходный код других используемых объектов смотрите в Git
При повторном возникновении ошибки «too_many_rows» обработка события пройдет по нашему сценарию «пользовательского» логирования. Таким образом мы можем ввести второй термин (в рамках данного цикла статей), «Пользовательские логирование» — это логирование всех ошибок, возникновение которых предполагается и ожидается при нештатной работе алгоритма. В итоге, пользователь получит читаемый текст ошибки с кодом «USR0003», также, мы же всегда сможем подсчитать количество ошибок с указанным кодом. В случае большого количества ошибок у нас на руках будет «живая» статистика частоты возникновения ошибки и их количества, что позволит нам выйти на руководство с предложением по доработке/оптимизации процесса.
Давайте рассмотрим еще один пример (кейс из реального случая), в момент когда процедура get_telnumber по id клиента находит один «активный» номер телефона иногда возникает ситуация, что номер телефона не принадлежит мобильному оператору. Ситуации бывают разные иногда указанный номер мог быть номером городской телефонной сети, иногда номером международного оператора, а иногда вообще набор из нескольких цифр и т.д. Основным требованием от бизнес-заказчика было использование номера телефона российских операторов мобильной связи. Поэтому было решено добавить проверку соответствия найденного номера некому «корректному» шаблону (строки с 18 по 29). В случае обнаружения некорректного номера, логировать данное событие отдельным кодом «USR0004» и типом «WRN». Добавим функцию проверки корректности номера телефона, если номер соответствует шаблону (требованиям), то вернем номер телефона, иначе пустое значение.
Исходный код демонстрационной процедуры
procedure p_get_telnumber(p_userid in number,
p_telnumber out number,
p_errcode out number,
p_errtext out varchar2)
is
v_objname varchar2(60) := utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(1));
v_telnumber client_telnumbers.telnumber%type;
v_newtelnumber client_telnumbers.telnumber%type;
v_msgcode messagelog.msgcode%type;
v_msgtext messagelog.msgtext%type;
begin
select telnumber
into v_telnumber
from client_telnumbers
where id = p_userid
and enddate = to_date('31.12.5999 23:59:59', 'dd.mm.yyyy hh24:mi:ss');
v_newtelnumber := f_check_telnumber(v_telnumber);
if v_newtelnumber is not null then
p_telnumber := v_telnumber;
p_errcode := 1;
else
-- Пользовательское логирование
v_msgcode := 'USR0004'; -- внутренний код
v_msgtext := pkg_msglog.f_get_errcode(v_msgcode,to_char(p_userid));
pkg_msglog.p_log_wrn(p_objname => v_objname,
p_msgcode => v_msgcode,
p_msgtext => v_msgtext,
p_paramvalue => 'p_userid = '||to_char(p_userid));
p_errcode := -1;
p_errtext := v_msgtext;
end if;
exception
-- Пользовательское логирование
when too_many_rows then
v_msgcode := 'USR0003'; -- внутренний код
v_msgtext := pkg_msglog.f_get_errcode(v_msgcode,to_char(p_userid));
pkg_msglog.p_log_wrn(p_objname => v_objname,
p_msgcode => v_msgcode,
p_msgtext => v_msgtext,
p_paramvalue => 'p_userid = '||to_char(p_userid));
p_errcode := -1;
p_errtext := v_msgtext;
-- Архитектурное логирование
when others then
pkg_msglog.p_log_archerr(p_objname => v_objname,
p_msgcode => SQLCODE,
p_msgtext => SQLERRM,
p_paramvalue => 'p_userid = '||to_char(p_userid),
p_backtrace => dbms_utility.format_error_backtrace);
raise;
end p_get_telnumber;
*Исходный код других используемых объектов смотрите в Git
После сбора статистических данных по конкретной ошибке с кодом «USR0004», руководству стало понятно, что ошибка актуальна и количество ошибок с течением времени не только не уменьшается, а наоборот растет с линейной прогрессией. В дальнейшем, были выявлены источники «кривых» данных и были установлены внутренние требования по первичной обработке номера телефона клиентов. В итоге, со временем количество ошибок уменьшилось до нуля. И этого нельзя было добиться до тех пор, пока у всех участвующих лиц не возникло понимание о масштабе проблемы.
Выполняя самый банальный запрос в таблицу лога с группировкой по типу сообщения (msgtype), имени объекта (objname) и вашему внутреннему коду ошибки (msgcode) за отдельный квартал, вы сможете увидеть реальную картинку частоты возникновения той или иной ошибки. Как только в вашей БД появляется ошибка с большим количеством повторений вы всегда сможете выявить это событие и принять решение об устранении.
Исходный код запроса
select msgtype,
objname,
msgcode,
count(*)
from messagelog
where insertdate between to_date('01.01.2021', 'dd.mm.yyyy') and to_date('31.03.2021', 'dd.mm.yyyy')
group by msgtype, objname, msgcode
order by 4 desc
Результат запроса:
*Исходный код других используемых объектов смотрите в Git
Заключение
В заключении наверное скажу банальную вещь, о том что ваша БД является сложным механизмом ежесекундно выполняющая рутинные операции. Прямо сейчас в БД могут происходить различные ошибки. Критичные, которые вы исправляете практически сразу или некритичные, о которых вы можете вообще не знать. И если у вас нет информации о подобных ошибках, то возникает вопрос: «Нужно ли их вообще исправлять? Или можно подождать до тех пор, пока проблема не всплывёт?». Вопрос наверное «риторический».
Я же данной статьёй хотел показать один из способов ведения логирования с кодированием отдельных событий. Данный метод требует некоторых «обязательств» от разработчика и в нынешнее время этого тяжело добиться. В следующей статье постараюсь показать один из способов мониторинга ошибок основанный напрямую по кодам ошибок созданных в текущей статье.
Спасибо за внимание.
I’ve a SQL query where if output is NULL it should not send warning .
l_sup_id NUMBER;
begin
SELECT per_all_assignments_f.supervisor_id
INTO l_sup_id
FROM per_all_assignments_f
WHERE person_id = p_person_id
AND trunc (sysdate) BETWEEN effective_start_date
AND effective_end_date
AND primary_flag = 'Y';
elsif (p_person_type = 'APPRAISER' AND l_sup_id IS NOT NULL) then
hr_utility.set_message(801, 'HR_51888_APR_APPRAISER_NULL');
hr_utility.raise_error;
end if;
Whenever l_sup_id is null according to logic
hr_utility.set_message(801, 'HR_51888_APR_APPRAISER_NULL');
should not be executed
But whenever l_sup_id is null I am getting
ORA-01403: no data found
error in logs
If l_sup_id is not null application working is fine
jarlh
42.1k8 gold badges45 silver badges63 bronze badges
asked Apr 28, 2015 at 6:52
5
From documentation,
NO_DATA_FOUND
A SELECT INTO statement returns no rows, or your program references a
deleted element in a nested table or an uninitialized element in an
index-by table.
In your PL/SQL code, the SELECT .. INTO statement returns no rows, thus it raises NO_DATA_FOUND error. It never goes to the next line, i.e. your IF-ELSE
construct.
If you want to continue the operation, then you need to handle the EXCEPTION gracefully.
For example,
SQL> SET serveroutput ON
SQL>
SQL> DECLARE
2 o_ename emp.ename%TYPE;
3 i_empno emp.empno%TYPE;
4 BEGIN
5 SELECT ename INTO o_ename FROM emp WHERE empno = i_empno;
6 -- Handle no_data_found
7 EXCEPTION
8 WHEN no_data_found THEN
9 -- do something
10 dbms_output.put_line('No records found for employee no '|| i_empno);
11 END;
12 /
No records found for employee no
PL/SQL procedure successfully completed.
SQL>
answered Apr 28, 2015 at 7:11
Lalit Kumar BLalit Kumar B
47.3k13 gold badges96 silver badges123 bronze badges
As the error suggests its pointing to NO DATA for the condition, to handle that you need to use «Exception Handling», Please see the code for the changes,
declare
l_sup_id NUMBER;
begin
SELECT per_all_assignments_f.supervisor_id
INTO l_sup_id
FROM per_all_assignments_f
WHERE person_id = p_person_id
AND trunc (sysdate) BETWEEN effective_start_date
AND effective_end_date
AND primary_flag = 'Y';
elsif (p_person_type = 'APPRAISER' AND l_sup_id IS NOT NULL) then
hr_utility.set_message(801, 'HR_51888_APR_APPRAISER_NULL');
hr_utility.raise_error;
end if;
--changes start
exception
when no_Data_found then
dbms_output.put_line('No data exists for lsup '|| l_sup_id)
--changes end
end;
Edit:
SQL> SELECT * FROM TESTEMP WHERE EMPNO=6677;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
6677 JUPITER CLERK 7902 17-DEC-80 800 20
SQL>
SQL> declare
2 l_count number;
3 begin
4 select comm into l_count from testemp where empno=6677 ;
5 DBMS_OUTPUT.PUT_LINE('lcount is'||l_count);
6 if (l_count IS NULL) then
7 dbms_output.put_line('no data');
8 else
9 dbms_output.put_line('data');
10 end if;
11 end;
12 /
lcount is
no data
PL/SQL procedure successfully completed.
Your condition wont go into the if at all if you compare to NULL or how ever you want to use it according to your specification
answered Apr 28, 2015 at 6:55
anudeepksanudeepks
1,0801 gold badge12 silver badges23 bronze badges
2
Thank you for all the responses.
Instead of plain sql I created the following cursor
cursor csr_supervisor_id
is
SELECT supervisor_id
FROM per_all_assignments_f
WHERE person_id = p_person_id
AND trunc (sysdate) BETWEEN effective_start_date
AND effective_end_date
AND primary_flag = 'Y';
and fetched it in l_sup_id
open csr_supervisor_id;
fetch csr_supervisor_id into l_sup_id;
Now no data received error is not coming.
answered Apr 28, 2015 at 7:55
I am getting ORA-01403: no data found
exception for the following query. What are the possibilities of this error?
SELECT trim(name)
INTO fullname
FROM ( SELECT n.name
FROM directory dir, store n
WHERE dir.name = n.name
AND dir.status NOT IN ('F', 'L', 'M')
ORDER BY n.imp, dir.date)
WHERE rownum <= 1;
How can I handle this error?
diziaq
6,78916 gold badges53 silver badges90 bronze badges
asked Jan 17, 2014 at 12:47
4
Although you have put a WHERE condition, a better way would be to handle case of record not found or ‘No Data Found’ error. I would write above code with wrapping the SELECT
statement with it’s own BEGIN/EXCEPTION/END
block.
Code could be something like this:
BEGIN
SELECT trim(name)
INTO fullName
FROM (
SELECT n.name
FROM directory dir, store n
WHERE dir.name = n.name
AND dir.STATUS NOT IN ('F','L','M')
ORDER BY n.imp, dir.date
)
WHERE rownum <= 1;
EXCEPTION
WHEN NO_DATA_FOUND THEN
fullName := NULL;
END;
answered Jan 17, 2014 at 12:59
SandeepSandeep
5585 silver badges7 bronze badges
4
If the standard exception handling described by Sandeep seems to much overhead (like in my case) and you’re fine with a NULL
or some individual <not found> value), you might just transform it like this:
select col into v_foo from bar where 1=0 -- would provoke ORA-01403
=> no ORA-01403 raised:
-- if NULL would be fine:
select (select col from bar where 1=0) into v_foo from dual
-- if individual "NOT_FOUND" value should be set to avoid standard exception handling:
-- (it depends on your col type, so it could e.g. be 'NOT_FOUND' or -1
-- or to_date( 'yyyy-mm-dd', '2100-01-01') )
select nvl( (select col from bar where 1=0), 'NOT_FOUND' ) into v_foo from dual
answered Feb 23, 2017 at 12:12
Andreas CovidiotAndreas Covidiot
4,2185 gold badges50 silver badges96 bronze badges
1
Probably because your Query
SELECT n.name
FROM directory dir,
store n
WHERE dir.name = n.name
AND dir.STATUS NOT IN ('F','L','M')
ORDER BY n.imp,
dir.date
is not returning any rows
answered Jan 17, 2014 at 12:53
A Nice GuyA Nice Guy
2,6764 gold badges30 silver badges53 bronze badges
If dir.status
has any nulls in your table, then not in
is probably not doing what you think it is. You may get zero rows even though you think you should get one or more rows. You can switch to and not (dir.status in ('F,'L','M'))
instead of dir.status not in ('F','L','M')
.
See this for reference.
answered Jan 17, 2014 at 15:40
GriffeyDogGriffeyDog
8,1463 gold badges22 silver badges34 bronze badges
forget the exceptions… just use the dual table:
select (
SELECT trim(name)
FROM ( SELECT n.name
FROM directory dir, store n
WHERE dir.name = n.name
AND dir.status NOT IN ('F', 'L', 'M')
ORDER BY n.imp, dir.date)
WHERE rownum <= 1
) into fullname
from dual;
B-) that way if your query don’t return anything the variable will be populated with null.
answered Sep 26, 2022 at 16:07
Автор признателен руководителям и сотрудникам ЗАО «Нефтегазсистемы»,
начальникам и персоналу вычислительных центров региональных управлений ОАО «Транснефть»,
c чьей помощью был разработан и внедрен данный Oracle-проект.
Возможные ошибки и методы их устранения
В
данном пункте приводится список ошибок с примерами сообщений на английском и
русском языке (через косую черту). Далее идет текст с указанием причины и
решения проблемы: сначала из фирменной документации, затем комментарий из
практики (чаще всего по решению проблемы, но иногда только по причине, если
решение проблемы ясно).
Ошибка ORA-00020
ORA-00020: maximum number of
processes (num) exceeded
/ превышено максимальное
количество процессов (ном)
По
документации:
Причина:
Операция потребовала ресурс,
оказавшийся недоступным. Максимальное количество процессов определяется
параметром инициализации PROCESSES.
Когда этот максимум превышается, никакие запросы больше обрабатываться не
могут.
Действие:
Повторите операцию еще раз через
несколько минут. Если это сообщение выдается часто, закройте ORACLE,
увеличьте параметр PROCESSES в файле
параметров инициализации, и запустите ORACLE вновь.
Из
практики:
Действие:
Требуется увеличить параметр PROCESSES в
файле INIT<SID>.ORA, причем для деф-сайта этот параметр должен
быть больше, чем для дест-сайта. Для БД СИСТЕМЫ было рекомендовано
установить этот параметр в 300 для дест-сайта и 400 для деф-сайта.
Ошибка ORA-00060
ORA-00060: deadlock detected
while waiting for resource
/ во время ожидания ресурса
произошла взаимоблокировка
По
документации:
Причина: Активный сеанс и какой-то другой сеанс, оба ожидающие
один и тот же ресурс, заблокировали друг друга. Это состояние известно как
взаимоблокировка. Для того, чтобы выйти из взаимоблокировки, надо сделать откат
(восстановить предыдущее состояние) одной или нескольких команд, таким образом
другой сеанс сможет продолжить работу.
Действие: Либо:
·
выдайте команду ROLLBACK и перезапустите все команды, входящие в последнюю транзакцию;
·
подождите, пока блокировка не
закончится (возможно, через несколько минут), и перезапустите те команды, на
которых произошел откат.
Из
практики:
Причина:
Ошибка может возникнуть при
перегенерации сайта на БД, куда был неудачно выполнен полный импорт БД другого
сайта (см. Часть 2, Глава 3: Перенос основной БД на сервер с другой ОС).
Действие: Попробуйте удалить мастер-группы вместе с объектами и
повторить генерацию сайта.
Ошибка ORA-00600
ORA-00600:
internal error code, arguments: [num],[?],[?],[?],[?],[?] ,[?],[?]
/ код внутренней ошибки,
аргументы: [ном],[?],[?],[?], [?],[?],[?],[?]
По
документации:
Причина:
Это общее внутреннее сообщение для
исключительных ситуаций программ ORACLE. Оно указывает, что процесс столкнулся с неожиданным
событием нижнего уровня. Причинами,
вызывающими это сообщение, могут быть:
·
истечение времени
ожидания;
·
поломка файла;
·
сбойные ситуации при проверке
данных в памяти;
·
сообщения ввода/вывода,
аппаратного обеспечения, памяти;
·
некорректно
восстановленные файлы.
Первый
аргумент — это номер внутреннего сообщения; другие аргументы — различные
числа, имена и символьные строки. (Для получения более полной информации см.
раздел «Обращение в службу поддержки пользователей ORACLE«.)
Числа могут меняться в зависимости от версии сервера ORACLE.
Действие:
Отправьте описание этой ошибки в
службу поддержки пользователей ORACLE, сопроводив его информацией о:
·
событиях, которые привели к
ошибке;
·
предпринятых вами действиях,
которые привели к ошибке;
·
состоянии операционной системы и ORACLE
на момент ошибки;
·
подробностях всех необычных
обстоятельств, предшествовавших получению сообщения ORA-00600;
·
содержимом всех файлов трассировок,
созданных в результате ошибки;
·
относящихся к этому случаю
реакциях сигнального файла.
Замечание:
необходимо знать предысторию ошибок,
произошедших в самое разное время до этой внутренней ошибки, поскольку именно
они и могут оказаться ее причиной.
Из
практики:
Действие:
Это одна из самых скверных ошибок.
При ее возникновении рекомендуется обратиться к группе технической поддержки Oracle.
Но существует также еще одна рекомендация: настройте работу в Oracle через
протокол IPC.
Ошибка ORA-01400
ORA-01400: cannot
insert NULL into (PLIPEKN.EDITIONS.ID)
/ Пропущен первичный ключ
или обязательный
(NOT NULL) столбец, или NULL во время операции INSERT
ORA-06512: at
«PLIPEKN.WORKS_LOG», line 16
ORA-04088: error
during execution of trigger ‘PLIPEKN.WORKS_LOG’
ORA-06512: at
«PLIPEKN.WORKS$RP», line 831
ORA-01085:
preceding errors in deferred rpc to «PLIPEKN.WORKS$RP. REP_UPDATE»
ORA-02063:
preceding 5 lines from PLI_NORD
По документации:
Причина: При вводе или редактировании записи Вы не задали
значение обязательного (NOT
NULL) столбца.
Действие: Задайте значение для каждого столбца NOT NULL или измените определение таблицы так, чтобы
разрешить устанавливать пустые значения столбцов.
Из
практики:
Причина:
Возникает при попытке сделать изменение
в таблице при отключенном или отсутствующем триггере EDITIONS_COR (который расчитывает и устанавливает системный
идентификатор записи ID).
Действие:
Включите (поставьте Enabled с
помощью Oracle Schema
Manager) либо создайте
триггер EDITIONS_COR:
create or replace
trigger EDITIONS_COR
before insert
or update on EDITIONS
for each row
begin
if INSERTING
then
select
EDITIONS_SEQ.nextval into :new.ID from DUAL;
end if;
:new.CORDATE:=SYSDATE;
:new.USERNAME:=USER;
end;
Ошибка ORA-01403
ORA-01403: data not found
/ данные не найдены
ORA-06512: на
«PLIPEKN.DRFEAT$RP», строки 321
ORA-01085: ошибка обработки в
задержанном rpc в «PLIPEKN.DRFEAT$RP. REP_UPDATE«
По
документации:
Причина: В программе на базовом языке были выбраны все записи.
Код возврата от операции FETCH равен +4. Это означает, что из запроса на были
извлечены все записи.
Действие: Прекратите обработку для данного оператора SELECT.
Из
практики:
Причина:
Ошибка ORA-01403 является большим сюрпризом. Она возникает в самом важном месте – при выполнении
удаленной транзакции, и, притом, из-за множества причин, большинство которых
Вам еще не известно. Эта трудно распознаваемая ошибка обязательно будет время
от времени у Вас возникать.
Действие:
Дело может быть в следующем: не
обновлено поле, по которому разрешаются конфликты (отключен или отсутствует
триггер ТАБЛИЦА_COR, который расчитывает и устанавливает поле CORDATE, по которому как раз и разрешаются конфликты методом Latest Timestamp — см. пример триггера _COR выше при описании ошибки ORA-01400). Эта ошибка не возникает, если транзакция по данной
записи идет одна, без встречной.
Ошибка ORA-01591
ORA-01591: lock held by
in-doubt distributed transaction 6.58.10015
/ блокировка, удерживаемая
распред. транзакцией 6.58.10015,
находящейся в неопр. сост.
По
документации:
Причина:
Была попытка доступа к ресурсу,
заблокированному «повисшей» распределенной транзакцией, находящейся в
состоянии подготовки.
Действие:
Для того, чтобы определить связь баз
данных и состояние транзакции, сравните номер транзакции в сообщении со
столбцом GLOBAL_TRAN_ID таблицы DBA_2PC_PENDING.
Попытайтесь исправить сетевое соединение для координатора и узла точки
завершения транзакции, если это необходимо. Если исправление временно невозможно,
обратитесь к администратору базы данных узла точки завершения транзакции (если
она известна), чтобы «протолкнуть» ожидающую какого-то действия
транзакцию.
Из
практики:
Причина:
Ошибка диагностирует возникновение
«смертельных объятий», зацикливании процессов друг на друге. Может возникнуть
при попытке удалить из мастер-группы дест-сайт, если одна из БД других
сайтов остановлена.
Действие:
Запустите БД всех сайтов и в
состоянии мастер-группы NORMAL повторите операцию.
Ошибка ORA-02049
ORA-02049: time-out:
distributed transaction waiting for lock
/ таймаут: распределенная
транзакция ждет блокировку
По
документации:
Причина:
Превышено время ожидания блокировки
распределенной транзакции. Это время задается в параметре инициализации DISTRIBUTED_LOCK_TIMEOUT.
Действие:
Эта ситуация трактуется как
тупиковая, поэтому происходит откат вашей команды. Установите в параметре
инициализации DISTRIBUTED_LOCK_TIMEOUT более длительный интервал времени ожидания; затем
закройте и перезапустите экземпляр СУБД.
Из
практики:
Причина:
Ошибка может порождаться при
возникновении «смертельных объятий», связанных с тем, что кончилось время
ожидания выполнения распределенной транзакции, заданное в конфигурационном
файле параметром DISTRIBUTED_LOCK_TIMEOUT.
Действие:
Увеличьте значение указанного
параметра и перезагрузите БД.
ПРИМЕЧАНИЕ 1.
На момент внедрения этот параметр можно снизить до 60
(1 мин), чтобы долго не ожидать результатов выполнения небольших тестов по
проверке репликации. Во время же эксплуатации лучше увеличить этот параметр,
например, до 300 (5 мин).
ПРИМЕЧАНИЕ 2.
Такое сообщение может появиться при выполнении
административных запросов, причем не адекватным образом, например, при переводе
группы в NORMAL, затем сразу в QUIESCED
(для проверки). Транзакций в этом случае быть не должно (кроме, возможно,
системных). Подождите немного и повторите попытку.
ПРИМЕЧАНИЕ 3.
Сообщение об этой ошибке однажды появилось при
одновременном добавлении сайта к двум мастер-группам (первой и последней),
причем таблицы обеих групп друг на друга не ссылались.
Ошибка ORA-02266
ORA-02266: unique/primary
keys in table referenced by enabled
foreign keys
/ таблица имеет некие уникальные/первичные
ключи,
на которые ссылаются внешние ключи
По
документации:
Причина: Была попытка уничтожить таблицу, хотя она имела еще
какие-то уникальные или первичные ключи, на которые имеются активные (enabled) ссылки внешних ключей.
Действие:
Перед удалением таблицы отключите все
ссылки внешних ключей на уникальные или первичные ключи. Посмотреть имеющиеся
ссылки и их статус Вы можете с помощью следующего SQL-запроса:
select
CONSTRAINT_NAME, TABLE_NAME, STATUS
from
USER_CONSTRAINTS
where
R_CONSTRAINT_NAME in (
select CONSTRAINT_NAME
from
USER_CONSTRAINTS
where
TABLE_NAME=’TABNAM’);
Из практики:
Причина:
Фирма Oracle
инструктирует, что эта ошибка возникает при попытке сделать DROP или TRUNCATE на
таблицу со связями. Но при репликации эта ошибка может возникнуть в случае,
если на дест-сайте таблица имеет статус Error.
Действие:
Для исправления ситуации требуется
приостановить мастер-группу (Suspend),
удалить таблицу (Remove) из
мастер-группы деф-сайта (не удаляя физически), дождаться удаления из дест-сайта,
затем опять ее добавить (Add) и
активизировать мастер-группу (Resume).
Ошибка ORA-02449
ORA-02449: unique/primary keys in table referenced by
foreign keys
/ уникальный/первичный
ключ в таблице,
на которую
ссылаются по внешнему ключу
По документации:
Причина: Была попытка уничтожить таблицу, хотя она имела еще
какие-то уникальные или первичные ключи, на которые ссылаются внешние ключи.
Действие:
Перед удалением таблицы удалите все
ссылки внешних ключей на уникальные или первичные ключи. Посмотреть имеющиеся
ссылки Вы можете с помощью следующего SQL-запроса:
select * from
USER_CONSTRAINTS where table_name = «TABNAM»;
Из практики:
Причина:
Возникает при попытке удалить таблицу
с первичным или уникальным ключем, если на нее ссылается другая таблица (см.
выше: ORA-02266).
Ошибка ORA-03113
ORA-03113:
end-of-file on communication channel
/ конец файла по
коммуникационному каналу
По документации:
Причина: По коммуникационному каналу передан сигнал
конца файла, который не был обработан соответствующим образом программным
обеспечением SQL*Net (двухзадачным программным обеспечением). Это
сообщение может быть выдано, если теневой двухзадачный процесс, связанный с SQL*Net, завершился ненормально, или же на устройстве связи
между процессами произошел физический сбой (сеть или сервер отключились от
коммуникации).
Действие: Если это сообщение было выдано при попытке
осуществить связь, проверьте установочные файлы для соответствующего драйвера SQL*Net и убедитесь, что программное обеспечение SQL*Net на сервере установлено правильно. Если сообщение было
выдано после того, как связь правильно установилась, и ошибка не связана с
физическим сбоем, проверьте файл трассировки, если таковой был создан на
сервере в момент сбоя. Существование файла трассировки может указать вам на то,
что эта ошибка — внутренняя ошибка ORACLE, требующая вмешательства
службы поддержки пользователей ORACLE.
Из практики:
При
возникновении этой ошибки рекомендуется посмотреть трассировочные файлы (обычно
находятся в каталоге RDBMS80TRACE). Как
правило, это связано с потерей связи или неисправностью на сервере, возникших
во время выполнения процесса в Oracle.
Эта
ошибка часто возникает при прохождении на сервер большого пакета транзакций или
подтверждений от них (см. Часть 2, Глава 3: Если пропала связь с сервером),
но может возникнуть и во время выполнения административных запросов (например,
одновременный запуск добавления достаточно больших таблиц в несколько
мастер-групп).
Конкретно
эта ошибка может возникнуть при попытке создания на удаленном сервере большой
таблицы (команда create table TAB as select * from USER.TAB@DBLINK или
аналогичный процесс в Мультимастере). В этом случае рекомендуется
послать администратору удаленного сервера дамп для импорта больших файлов
(можно целой группы или всей БД), а затем лишь сгенерить репликационную
поддержку для этих таблиц.
Ошибка ORA-04030
ORA-04030: out of
process memory when trying to allocate 524316 bytes
(pga heap, KSFQ Buffers)
/ выход за пределы
памяти процесса при попытке выделить
524316 байт (стр)
По
документации:
Причина:
Собственная память системного
процесса исчерпана.
Действие:
Попросите администратора базы данных
или администратора операционной системы увеличить квоту памяти процессу. В
приложении может быть ошибка, которая и приводит к чрезмерному потреблению
памяти процесса.
Из
практики:
Выделяемая
под процессы память на сервере исчерпалась. Причины могут быть разные. На Netware-сервере
это обычно происходит при фрагментации кэш-памяти и помогает только
перезагрузка сервера.
Ошибка ORA-04052
ORA-04052: error
occurred when looking up remote object
REPADMIN.SYS @ULAN.WORLD
/ ошибка возникла
во время поиска удаленного объекта
REPADMIN.SYS
@ULAN.WORLD
ORA-00604: error
occurred at recursive SQL level 2
ORA-12154:
TNS:could not resolve service name
ORA-06512: at
«SYS.DBMS_REPCAT_MAS», line 674
ORA-06512: at
«SYS.DBMS_REPCAT», line 516
ORA-06512: at line 2
По
документации:
Причина:
Ошибка возникла во время поиска
удаленного объекта.
Действие:
Исправьте ошибку. Убедитесь, что на
удаленной базе данных были запущены все необходимые командные файлы создания
представлений данных, используемых для запроса/поиска объектов базы данных. См.
книгу Сервер ORACLE7. Руководство администратора.
Из практики:
Причина: Ошибка может возникнуть при ручном «толкании»
административных запросов (Apply all admin requests now).
Действие: Посмотрите, не «уронили» ли Вы при этом сервер. Если
да – перезапустите его.
Ошибка ORA-06502
ORA-06502: PL/SQL:
numeric or value error
/ PL/SQL: ошибка в числе или в
значении
По документации:
Причина: Произошла ошибка арифметическая, числовая, строковая,
преобразования или правила целостности. Например, такая ошибка может произойти
при попытке присвоить значение NULL
переменной, описанной как NOT NULL, или при
попытке присвоить целое, больше переменной, описанной как NUMBER(2).
Действие: Измените данные, которыми вы манипулируете, или их
описание таким образом, чтобы они не противоречили друг другу.
Из практики:
Причина:
Ошибка может возникнуть при
перегенерации сайта на БД, куда уже был выполнен полный импорт БД другого сайта
(см. Часть 2, Глава 3: Перенос основной БД на сервер с другой ОС).
Действие: Необходимо удалить мастер-группы вместе с объектами и
повторить генерацию сайта (на самом деле так просто отделаться от этой ошибки
не всегда удается).
Ошибка ORA-12011
ORA-12011: execution of 1
jobs failed
/ сбой при выполнении 1
задания
ORA-06512: at «SYS.DBMS_IJOB», line 255
ORA-06512: at «SYS.DBMS_JOB»,
line 218
ORA-06512: at line 2
По
документации:
Причина:
DBMS_IJOB.RUN обнаружил ошибку. Запуск одного или нескольких
заданий привел к ошибке, которую не удалось обработать.
Действие:
Посмотрите в журнале предупреждений,
какое задание не смогло запуститься и почему.
Из
практики:
Причина:
Ошибка возникает при попытке
запустить задачу PUSH, которая до этого
находилась в состоянии BROKEN, причем, предварительный перевод ее в состояние NORMAL не помогает –
задача или сама через некоторое время устанавливается в BROKEN, или это происходит после попытки ее запустить. Это может произойти по
причине выполненного ранее выполнилось автоматически при установке в это
состояние пакета транзакций).
Ошибка ORA-23308
ORA-23308: object
PLIPEKN.COUNTRY$RU does not exist or is invalid
/ объект PLIPEKN.COUNTRY$RU
либо неправильный,
либо не
существует
По
документации:
Причина:
Указанное имя введено неправильно или
пусто, заданный тип неправилен, объект не является правильным объектом базы данных
или не существует как тиражируемый объект с соответствующим состоянием.
Действие:
Проверьте, что объект существует,
доступен пользователю и, если требуется, является правильным объектом в списке ALL_REPOBJECT.
Из
практики:
Причина:
Ошибка возникает при несоответствии
структуры таблицы одного сайта с другим (например, при перегенерации
репликационной поддержки).
Действие:
Тщательно сверьте структуру указанной
таблицы на деф-сайте и дест-сайте. Возможно, на деф-сайте
была изменена ее структура, типы полей или ограничения вне DDL-механизма ORM.
ВНИМАНИЕ
!
Эта ошибка может создать заколдованный круг: при ее удалении на дест-сайте вне
DDL-механизма ORM остаются неудаленными $RP и $RR модули и операции Remove
затем Add для этой таблицы на деф-сайте вызывает ошибку.
Удаление вышеназванных модулей тоже не помогает. Не помогает также
соответствующая операция alter
table для этой таблицы в БД дест-сайта
(вне ORM). При попытке удаления этой таблицы из мастер-группы деф-сайта
(с тем, чтобы это удаление распространилось на дест-сайт) также
возникает ошибочный административный запрос, поскольку из мастер-группы дест-сайта
в этом случае нельзя удалить таблицу с несоответствующей структурой.
Рекомендуется следующее: сделайте соответствующую
операцию alter
table для этой таблицы в БД дест-сайта
через механизм ORM. Если при этом также возникнет ошибка можно поступить
иначе: удалите таблицу из БД дест-сайта с помощью SQL*Plus
(отключив предварительно ограничения) и создайте заново (можно пустую). Затем
можно попытаться удалить эту таблицу из мастер-группы деф-сайта,
подождать окончания административного запроса на обоих сайтах и вновь добавив
таблицу в мастер-группу. Если и это не поможет, то пересоздайте всю
мастер-группу путем удаления и последующего подключения к ней этого сайта с
отключенной опцией Use
existing object.
Ошибка ORA-23309
ORA-23309: object
PLIPEKN.COUNTRY of type TABLE exists
/ объект PLIPEKN.COUNTRY типа
TABLE существует
По документации:
Причина: Объект уже существует в том же пространстве имен,
возможно с другим типом или формой.
Действие: Удалите объект или повторите запрос со значением
TRUE логического параметра RETRY или USE_EXISTING_OBJECT.
Из
практики:
Причина:
Ошибка может возникнуть после
добавления на мастер-группу деф-сайта нового дест-сайта, если на дест-сайте
уже есть такая таблица, но ее структура другая. Ошибка возникает независимо от
того, была ли включена или отключена опция Use existing object при создании мастер-группы и включении в нее таблиц
на дест-сайте.
Действие:
Удалите эту таблицу в БД дест-сайта
и повторите добавление этого сайта на мастер-группу дест-сайта.
Ошибка ORA-23312
ORA-23312: not
the masterdef according to …
/ не masterdef согласно …
По документации:
Причина: Имя схемы пусто или неправильно введено,
запрашиваемая заданная база данных не является оригиналом, или один из
оригиналов не считает вызываемую базу данных оригиналом.
Действие:
Если заданное имя схемы и оригинала
правильны, соединитесь с оригиналом и повторите запрос, или переместите masterdef, использовав RELOCATE_masterdef.
Из
практики:
Причина:
Ошибка может возникнуть при
перегенерации репликационной поддержки для сайта, где объекты имеют статус Error (см. Часть 2, Глава 3: Работа с административными запросами, Решение
проблем при создании мастер-групп).
Действие: Удалите всю группу с объектами с этого сайта (или
только Error-объекты) и перегенерите репликацию.
Ошибка ORA-23313
ORA-23313: object
group PLIPEKN7 is not mastered at PLI_BONN.WORLD
/ схема PLIPEKN7 не явл.главной для PLI_BONN.WORLD
По документации:
Причина:
Имя схемы пусто или неправильно
введено, запрашиваемая база данных не является оригиналом или запрашиваемая
база данных не считает заданную базу данных оригиналом.
Действие:
Если заданное имя схемы правильно,
соединитесь с текущим оригиналом и повторите запрос, установите запрашиваемую
базу данных оригиналом с помощью ADD_MASTER_DATABASE или используйте SWITCH_SNAPSHOT_MASTER, если запрашиваемая база данных является узлом копии.
Из практики:
Причина:
Ошибка возникает, если мастер-БД с
мастер-группы деф-сайта уже удалена.
Ошибка ORA-23374
ORA-23374: object
group PLIPEKN0 already exists
/ мастер—группа PLIPEKN0 уже существует
ORA-06512: at
«SYS.DBMS_SYS_ERROR», line 86
ORA-06512: at
«SYS.DBMS_REPCAT_MAS», line 1598
ORA-06512: at
«SYS.DBMS_REPCAT», line 113
ORA-06512: at line 2
По документации:
Причина: Данная мастер-БД уже реплицирована данной
мастер-группой.
Действие: Выберите другую мастер-группу или мастер-БД.
Из практики:
Причина:
Ошибка возникает при попытке
«прицепить» дест-сайт к мастер-группе деф-сайта, если на этом дест-сайте
такая мастер-группа уже существует. Эта ситуация возникает, если сайт пытаются
пересоздать (см. Часть 2, Глава 3: Пересоздание дест-сайта), для чего
сначала его «отрывают» от мастер-группы деф-сайта, а потом (переведя ее
в состояние QUIESCED) пытаются опять присоединить.
Действие: Удалите в режиме NORMAL мастер-группу с дест-сайта
со всеми ее объектами, т.е. отметьте опцию Drop all objects in the group (на предупреждение, что объекты группы сохранятся на
других сайтах – нажмите OK). Затем повторите присоединение (Properties… => Destinations => Add… => Asysnc, Use
existing objects, Copy row
data).
SQL-команды по анализу и управлению репликацией
Нижеприведенные команды SQL и PL/SQL окажутся для администратора Oracle
полезными и часто необходимыми для.
анализа и управления распределенными транзакциями. Полный синтаксис
использования DBMS-процедур и структура представлений Словаря данных
приводятся в Приложении 3 и Приложении 4, соответственно.
Анализ объектов в мастер-группе
·
Поиск мастер-группы для таблицы
(например, BRANCH):
select GNAME from
ALL_REPOBJECT
where
ONAME=’BRANCH’ and TYPE=’TABLE’;
·
Кол-во записей по всем таблицам
мастер-группы (пример для PLIPEKN0). Используйте скрипт RowCntMg.sql (предварительно исправив в нем название нужной
мастер-группы или аналогичные скрипты для каждой мастер-группы: RwCntMg0.sql, …, RwCntMg7.sql), который формирует скрипт Temp.sql и запускает его
(создан по прототипу известного скрипта TabCount.sql автора Peter Koletzke):
Листинг скрипта
на подсчет записей всех таблиц БД
set echo off
set feed off
set term off
set head off
set pages 10000
col L newline
————————————————————
spool temp.sql
————————————————————
prompt set head off
prompt set feed off
prompt set term on
prompt set recsep off
—prompt set echo off
prompt variable iC number;;
prompt execute :iC:=0;;
prompt begin
select
‘select :iC + count(*) into :iC’,’from
‘||T.TABLE_NAME||’;’ L
from
ALL_REPOBJECT R, USER_TABLES T
where
R.GNAME=’PLIPEKN0′ and R.TYPE=’TABLE’ and
R.ONAME = T.TABLE_NAME
/
prompt end;;
prompt /
prompt select :iC from DUAL;;
—prompt set feed on
spool off
————————————————————
set term on
set pages 0
————————————————————
@temp
————————————————————
set pages 23
set feed on
set head on
Сформированный и
запускаемый далее скрипт Temp.sql имеет следующий вид:
set
head off
set
feed off
set
term on
set
recsep off
variable
iC number;
execute
:iC:=0;
begin
select :iC + count(*) into :iC from BRANCH;
select :iC + count(*) into :iC from CONOPF;
.
.
.
select
:iC + count(*) into :iC from TYPEM;
select
:iC + count(*) into :iC from TYPEOBJECT;
end;
/
select
:iC from DUAL;
/
·
Кол-во модулей по всем
мастер-группам (если объекты – только
таблицы, то равно учетверенному кол-ву таблиц – Package и Package Body по
модулям $RP и $RR):
select count(*) from
ALL_REPGENERATED order by ONAME, TYPE;
·
Кол-во модулей по каждой
мастер-группе (очень полезный запрос):
select GNAME,
count(*) from ALL_REPOBJECT
where
TYPE=’TABLE’
group by GNAME
order by GNAME;
·
Объекты, нуждающиеся в перегенерации
репликационной поддержки:
select ONAME from
ALL_REPOBJECT
where
(GENERATION_STATUS <> ‘GENERATED’) and TYPE=’TABLE’;
·
Error-объекты на сайте (обязателен к применению):
select GNAME,
ONAME from ALL_REPOBJECT
where
STATUS=’ERROR’ and TYPE=’TABLE’ order by GNAME;
·
Кол-во Error-объектов по мастер-группам:
select GNAME,
count(*) from ALL_REPOBJECT
where
STATUS=’ERROR’ and TYPE=’TABLE’
group by GNAME
order by GNAME;
·
Кол-во изменений по мастер-группам
за период времени (для определения
наиболее активных мастер-групп):
select R.GNAME,
count(A.ID) CNT
from
ALL_REPOBJECT R, EDITIONS A
where
R.TYPE=’TABLE’
and R.ONAME=A.TABNAME and
trunc(A.CORDATE)=trunc(SYSDATE-1)
group by R.GNAME
order by
count(A.ID);
Результат выполнения запроса (пример):
GNAME CNT
——————————
———
PLIPEKN6
4
PLIPEKN0
6
PLIPEKN4
35
PLIPEKN5
93
PLIPEKN3
143
Анализ административных запросов
·
Ошибочные административные
запросы по таблицам (некоторые
ошибки, в частности, end—of—file…, могут
не войти):
select
ID, to_char(TIMESTAMP,’DD.MM.YYYY HH24:MI:SS’) TIME,
substr(MASTER,1,15) MR, substr(GNAME,1,8) GR,
substr(ONAME,1,12) OB, substr(MESSAGE,1,40)
from
USER_REPCATLOG
where
STATUS=’ERROR’ and TYPE=’TABLE’;
·
Административные запросы по
мастер-группе (PLIPEKNn):
select
ID, to_char(TIMESTAMP,’DD.MM.YYYY HH24:MI:SS’) TIME,
substr(MASTER,1,15) MAST, substr(ONAME,1,12) OB,
STATUS, REQUEST, ERRNUM
from
USER_REPCATLOG
where
GNAME=’PLIPEKN0′
order
by ID;
·
Административные запросы по
мастер-сайту первой очереди (для
выявления блокирующих административных запросов):
select
ID, to_char(TIMESTAMP,’DD.MM.YYYY HH24:MI:SS’) TIME,
substr(MASTER,1,15) M, substr(GNAME,1,12) G,
substr(ONAME,1,12) O, STATUS, REQUEST, ERRNUM
from
USER_REPCATLOG
where
ROWNUM < 10;
·
Кол-во адм-запросов по всему
мастер-сайту (для общего контроля
выполнения):
select count(*) from
USER_REPCATLOG;
·
Кол-во административных
запросов по каждой мастер-группе (для
общего контроля выполнения):
select
substr(GNAME,1,12) GR, count(*) REQ_NUM
from
USER_REPCATLOG
group
by GNAME
order
by GNAME;
·
Кол-во каждого вида и статуса
административных запросов по каждой мастер-группе (для детального контроля выполнения):
select
substr(GNAME,1,12) GR, REQUEST, STATUS, count(*) REQ_NUM
from
USER_REPCATLOG
group
by
GNAME, REQUEST, STATUS
order
by
GNAME, REQUEST, STATUS
;
Анализ транзакций
·
Кол-во всех транзакций:
select count(*) from
DEFTRAN;
·
Кол-во транзакций для каждого
сайта:
select
substr(DBLINK,1,20), count(*) CNT from DEFTRANDEST
group by DBLINK
order by DBLINK;
·
Кол-во транзакций для каждого
сайта по дням формирования:
select
substr(DD.DBLINK,1,20) DL,
trunc(D.START_TIME) ST,
count(DD.DEFERRED_TRAN_ID) CT
from
DEFTRANDEST DD,
DEFTRAN D
where
DD.DEFERRED_TRAN_ID=D.DEFERRED_TRAN_ID
group by
substr(DD.DBLINK,1,20), trunc(D.START_TIME)
order by
DL, ST
;
Результат выполнения запроса (пример):
DL
ST CT
———————
——— ———
PLI_ANTA.WORLD
29-FEB-00 939
PLI_ANTA.WORLD
01-MAR-00 6160
PLI_ANTA.WORLD
02-MAR-00 7546
PLI_ANTA.WORLD
03-MAR-00 245
PLI_ANTA.WORLD
25-FEB-00 1580
PLI_ANTA.WORLD
26-FEB-00 570
PLI_ANTA.WORLD
27-FEB-00 165
PLI_ANTA.WORLD
28-FEB-00 8753
PLI_ANTA.WORLD
29-FEB-00 7491
PLI_ANTA.WORLD
01-MAR-00 6160
PLI_ANTA.WORLD
02-MAR-00 7546
PLI_ANTA.WORLD
03-MAR-00 245
12
rows selected.
·
Удаление транзакций. Для удаления одной транзакции (например, с
идентификатором 6.19.11941) используется следующее DBMS-предложение (значение NULL параметра DESTINATION указывает
о применении команды ко всем мастер-сайтам):
begin
DBMS_DEFER_SYS.DELETE_TRAN(
deferred_tran_id => ‘6.19.11941’,
destination
=> NULL);
end;
/
Для удаления всех транзакций используется пустое
значение параметра DEFERRED_TRAN_ID:
begin
DBMS_DEFER_SYS.DELETE_TRAN(
deferred_tran_id => »,
destination => NULL);
end;
/
·
Перезапуск транзакций: данная функция отсутствует, но можно использовать
запуск соответствующей задачи, т.е. процесс PUSH для нужного дест-сайта,
например:
DBMS_JOB.RUN(job
=> 204);
·
Кол-во ошибочных транзакций:
select count(*)
from DEFERROR;
·
Удаление всех ошибочных
транзакций. Для удаления ошибочной
транзакции (например, с идентификатором 8.55.21) используется
нижеприведенная DBMS-процедура (значение NULL параметра
DESTINATION указывает
о применении команды ко всем мастер-сайтам). Если значение параметра DEFERRED_TRAN_ID не
указано (=>’’), то удаляются все ошибочные транзакции (см. RemErr.sql):
begin
DBMS_DEFER_SYS.DELETE_ERROR(
deferred_tran_id => ‘8.55.21’,
destination => NULL);
end;
/
·
Перезапуск ошибочных транзакций. Для перезапуска ошибочной транзакции (например, с
идентификатором 8.55.21) используется нижеприведенная DBMS-процедура (параметр DESTINATION не
должен иметь значение NULL, а
указывать на требуемый мастер-сайт). Если значение параметра DEFERRED_TRAN_ID не
указано (=>’’), то перезапускаются все ошибочные транзакции:
begin
DBMS_DEFER_SYS.EXECUTE_ERROR(
deferred_tran_id => ‘8.55.21’,
destination => ‘PLI_ANTA’);
end;
/
Анализ журнала правок БД (EDITIONS)
В БД
рекомендуется создать и использовать специальную таблицу (например, EDITIONS), куда триггерами ТАБЛИЦА_LOG заносятся все изменения по таблицам
Вашей системы (находящимся только в БД Oracle). Анализ
этой таблицы полезен для сверки с выполненными и выполняемыми транзакциями.
Ниже приведен ряд полезных запросов (находятся в файле ShwAllEd.sql):
— Сводка по таблицам и датам последних правок
select TABNAME, count(TABNAME)
C, max(CORDATE) D
from EDITIONS
/*where CORDATE>SYSDATE-5*/
group by TABNAME
order by TABNAME;
— Сводка по видам правок за диапазон дат
select ACTION, count(ACTION)
C
from EDITIONS
where trunc(CORDATE)
between trunc(SYSDATE)-2 and trunc(SYSDATE)
group by ACTION
order by ACTION;
Пример
результата данного запроса (ACTION=1,2,3 – добавление,
изменение, удаление):
ACTION C
——— ———
1 431
2 247
3 44
— where to_char(CORDATE,’dd.mm.yy’)=to_char(SYSDATE-1,
‘dd.mm.yy’)
select TABNAME, count(TABNAME)
C
from EDITIONS
where trunc(CORDATE)=trunc(SYSDATE-1)
and ACTION=1
group by TABNAME
order by TABNAME;
— Сводка по таблицам, которые правились за
предыдущие дни
select TABNAME, count(TABNAME)
C
from EDITIONS
where trunc(CORDATE)>trunc(SYSDATE-2)
group by TABNAME
order by TABNAME;
— Все изменения (добавления) за день (для сверки с
репликацией)
select TABNAME,TABKEY,ACTION,to_char(CORDATE,’dd.mm.yy
hh:mi:ss’) DL
from EDITIONS
where to_char(CORDATE,’dd.mm.yy’)=to_char(SYSDATE-1,’dd.mm.yyyy’)
— and ACTION=1
order by CORDATE;
— Общее кол-во изменений за день
select count(*) CNT
from EDITIONS
where to_char(CORDATE,’dd.mm.yyyy’)=to_char(SYSDATE,’dd.mm.yyyy’)
and ACTION=1;
— Выборка добавленных в таблицу записей за 1 день
select T.ID, T.NAME, A.CORDATE
from PIPECROSS T, EDITIONS
A
where trunc(T.CORDATE)=trunc(SYSDATE-1)
and T.ID=A.TABKEY and A.TABNAME=’PIPECROSS’
and A.ACTION=1
and trunc(A.CORDATE)=trunc(SYSDATE-1)
order by A.CORDATE;
Необходимые конфигурационные параметры для репликаци
В этом пункте перечислены параметры конфигурационного
файла INIT<SID>.ORA, являющиеся важными для работы приложений. Эти
параметры должны иметь следующие значения.
·
DISTRIBUTED_LOCK_TIMEOUT = 300;
·
DISTRIBUTED_TRANSACTIONS
= 5 (для
репликации Мультимастер увеличить до 12-20);
·
GLOBAL_NAMES = TRUE;
·
JOB_QUEUE_INTERVAL = 10;
·
JOB_QUEUE_PROCESSES = 4 (для репликации Мультимастер
увеличить до 10 — 12, т.е., примерно, удвоенное кол-во мастер-сайтов);
·
OPEN_LINKS = 10;
·
PARALLEL_MAX_SERVERS = 10;
·
PARALLEL_MIN_SERVERS = 2;
·
REPLICATION_DEPENDENCY_TRACKING =
TRUE;
·
SHARED_POOL_SIZE – не менее 18000000, но не
более 40% ОЗУ сервера (если кроме Oracle на сервере не выполняются другие процессы), а если на сервере уже
установлены другие экземпляры Oracle (например, другая система или учебная БД), то сумма этих параметров не
должна превышать 40% ОЗУ;
·
DML_LOCK – не менее 300;
·
PROCESSES = 200 (при использовании репликации Мультимастер
увеличить: 300 на destination-сайте, 400 на definition-сайте).