Привет! Я работаю в компании Bercut и мы более 20 лет занимаемся разработкой и поддержкой ПО для операторов сотовой и фиксированной связи. Я прошел путь от инженера в отделе сопровождения до менеджера продукта. В последние годы работаю ведущим специалистом в отделе администрирования (Senior DBA) и знаю все про работу высоконагруженных биллинговых базах данных, обслуживающих от сотен тысяч до десятков миллионов абонентов. Сегодня я хочу рассказать о наших подходах к сокращению времени простоя продуктивного комплекса при установке обновлений схемы данных (далее — патчей) на СУБД Oracle. Обновление ПО выполняется в период минимальной нагрузки на комплекс, в то временное окно, когда будет оказано минимальное влияние на пользователей и бизнес. У временного окна есть определенные границы, например 3–4 часа, с 01 до 05 утра. В это окно нужно уложить все активности по включению режима ограниченного обслуживания, активации by‑pass режимов (для того чтобы абоненты могли звонить без участия биллинга) и остановке ряда модулей; произвести установку обновления на БД и обновить сами модули; выполнить тесты, активировать все сервисы и выполнить контрольные проверки бизнес функций. Описанные в статье методы и практики ориентированы на сокращение времени простоя/периода оказания сервиса с ограничениями в момент обновления комплекса. Данная статья скорее обзор «лучших практик» по разработке, тестированию и запуску скриптов установки патчей, миграции данных и тд. В статье описаны различные подходы и варианты по минимизации времени простоя комплекса, методика выявления узких мест, а также средства контроля и мониторинга процесса установки. Более детальные сведения по конкретным решениям Вы сможете найти в документации.  Статья состоит из двух частей. В первой части рассматриваются решения по ускорению установки патчей, во второй части будут описаны действия по подготовке, мониторингу процесса установки и диагностики проблем. Патч это набор скриптов, выполняемых с помощью утилиты для работы с БД — sqlplus.exe. В компании типовой патч состоит из исполняемого сценария install.bat, главного файла последовательности установки install.sql, конфигурационого файла install_config.sql, файла с локализованными текстами localize.sql и директориями с файлами устанавливаемых объектов БД и скриптами с дополнительными файлами последовательности установки install.sql. Могут быть также дополнительные исполняемые сценарии апгрейда в несколько этапов. На следующем скриншоте представлена типовая структура патча: При разработке патча учитывается, что патч может быть установлен как на небольшую абонентскую БД, так и на БД с миллионами абонентов. При этом процесс установки патча должен укладываться в выделенное окно и чем оно меньше, тем меньше потери бизнеса от простоя комплекса. Для сокращения времени установки патча могут быть использованы различные методы распараллеливания, а степень параметризации настраивается в конфигурационном файле патча. Для разных этапов и шагов установки могут быть использованы отдельные параметры. Примеры определения параметров для управления степенью распараллеливания и размером пакета: Распараллеливание — выполнение какой то операции при установке патча на БД в нескольких потоках, с целью сокращения общего времени работы комплекса в условиях оказания сервисов с ограничениями. Следует применять подходящие методы исходя из разумных соображений, чтобы уложиться в требуемое окно, например, не более 1 часа на установку патча на БД. При оценке необходимости использования тех или иных методов следует учитывать те БД и объемы данных в них, на которые патч будет устанавливаться. Если какая то операция быстро выполняется на маленькой БД, это вовсе не означает что она будет также отрабатывать за удовлетворительное время на большой БД. У разработчика должно быть как минимум понимание объемов данных, с которыми он работает, а лучше — должен быть доступ до тестовых БД с большими объемами, на которых он сможет выполнить оценку необходимости применения методов сокращения времени выполнения операции. В то же время, если операция одинаково быстро выполняется и на маленьких и на больших объемах данных, это означает, что никакие методы применять не требуется; достаточно выполнения обычных манипуляций с данными или схемой данных. Таким образом, методы распараллеливания применяются исходя из целесообразности и необходимости. И в любом случае следует придерживаться метода KISS — Keep It Simple. В следующей табличке сведены типовые задачи и типовые решения: Типовая задача Типовое решение для Enterprise Edition Типовое решение для Standard Edition Создание индекса на большую таблицу Parallel DDL :-( Создание большой таблицы на основе данных других таблиц CTAS, Parallel DDL :-( Создание ограничения целостности на большую таблицу Parallel DDL или 2-х фазное создание 2-х фазное создание Обновление данных в одной таблице Parallel DML DBMS_PARALLEL_EXECUTE или самописные скрипты Комплексное обновление данных в одной или нескольких таблиц DBMS_PARALLEL_EXECUTE или самописные скрипты DBMS_PARALLEL_EXECUTE или самописные скрипты Реорганизация большой таблицы, например с целью секционирования CTAS или DBMS_REDEFINITION или самописные скрипты в несколько фаз Cамописные скрипты в несколько фаз Удаление данных из большой таблицы Parallel DML или CTAS DBMS_PARALLEL_EXECUTE или самописные скрипты Далее все эти методы будут разобраны на примерах, но сначала о важной настройке самого экземпляра БД: Биллинг является высоконагруженной OLTP системой, с тысячами или десятками тысяч транзакций в секунду. Много различных сессий разных приложений вставляют, изменяют, удаляют или читают строки. Большинство транзакций короткие, изменяющие 1 или несколько строк. Для такого режима работы параллельное выполнение операций не требуется и бывает даже вредным. Параллельное выполнение какого то тяжелого процесса, читающего или изменяющего большие объемы данных может создать существенную нагрузку на CPU и СХД и навредить другим сессиям с множеством коротких, но критичных ко времени отклика транзакциям. Поэтому обычно возможность параллельного выполнения искусственно ограничивается, для этого значение параметра экземпляра БД parallel_max_servers администраторами БД выставляется в околонулевое значение. В тоже время, во время ночных работ по обновлению БД или выполнения каких либо maintenance операций может потребоваться распараллеливание этих операций. Поэтому, если при установке патча или выполнении подобных работ требуется выполнение операций с распараллеливанием, следует перед началом работ увеличить значение параметра parallel_max_servers. Возможным значением может быть число, равное числу процессорных ядер в сервере БД. Если планируется запускать несколько сессий с параллельным выполнением, то может потребоваться и большее значение. После окончания работ рекомендуется вернуться к старому значению параметра. DDL — Data Definition Language — группа операторов языка SQL для определения структуры данных. С помощью этих операторов можно создавать, изменять и удалять таблицы, индексы, процедуры и тд. Операторы CREATE, ALTER и DROP используются соответственно для создания, изменения и удаления объектов схемы. GRANT и REVOKE для выдачи и изъятия привилегий и ролей; имеется также ряд других операторов типа TRUNCATE, COMMENT, AUDIT и пр, впрочем которые уже не нуждаются в распараллеливании. DDL операторы, создающие или изменяющие большой объект в БД, могут выполняться долго и их время выполнения можно попытаться сократить за счет использования операнда PARALLEL. Примеры: В первом примере желаемая степень распараллеливания задана в коде (16), а во втором и третьем — параметризована. В момент параллельного выполнения команды в списке сессий можно наблюдать Pxxx процессы, выполняющую запущенную задачу в несколько потоков. Необходимость в использовании операнда PARALLEL определяет разработчик на основе знаний о том, большой или нет определяется объект. Количество параллельных процессов определяется инженером/администратором БД, устанавливающим патч, исходя из конфигурации оборудования, числа ядер и настроенных ограничений на параллельное выполнение на стороне БД. Пример: Задача: Создать две новые таблицы, одна из которых содержит список тарифных планов, а вторая — историю платежей абонентов. Создать индекс на уже существующую таблицу, в которой у разных заказчиков содержится от 3 до 300 млн записей. Решение: Для обоих новых таблиц распараллеливание при создании таблиц не требуется, потому что они создаются впервые и объекты будут иметь нулевой размер. При создании индекса нужно использовать PARALLEL &degree, где значение параметра &degree будет задаваться в конфигурационном файле в зависимости от конфигурации оборудования в каждом конкретном случае инженером по внедрению непосредственно при установке. В OLTP системе после создания или изменения объекта с PARALLEL я рекомендую обязательно изменить свойство объекта degree на 0. Например, ALTER INDEX index_name NOPARALEL; Это позволит исключить нежелательное срабатывание параллельного выполнения запросов с использованием объекта в дальнейшем. DML — Data Manupulation Language — это группа операторов для манипуляции данными. С помощью этих операторов можно добавлять, изменять, удалять строки в БД. Операторы INSERT, UPDATE, DELETE, MERGE используются соответственно для вставки, изменения, удаления и вставки или замены строк. Параллельное выполнение DML использует отличные от однопоточного выполнения DML механизмы блокирования, обработки транзакций и выделения места и по умолчанию параллельное выполнение DML выключено. Там, где явно требуется выполнить какой то DML параллельно, его необходимо явно включить. В приведенном ниже примере наглядно видно, что указание подсказки оптимизатору PARALLEL для оператора DML update хоть и приводит к тому, что оптимизатор Oracle формирует план параллельного выполнения с характерными признаками, но снизу имеется приписка, что параллельное выполнение отключено. В приведенном ниже примере наглядно видно, что указание хинта PARALLEL для оператора DML update хоть и приводит к тому, что Oracle формирует план параллельного выполнения, но только в части выборки данных (Parallel Query). Сам UPDATE будет выполняться уже однопоточно - снизу имеется приписка о том, что параллельное выполнение отключено.   Параллельное выполнение следует разрешить явно либо изменением текущей сессии: либо, начиная с Oracle 12, путем указания дополнительной подсказки ENABLE_PARALLEL_DML: В результате план параллельного выполнения UPDATE будет выглядеть следующим образом:   Проверить, включен ли режим параллельного выполнения, можно, обратившись к атрибутам текущей сессии PDML_STATUS: Вопросы мониторинга длительного однопоточного и параллельного выполнения будут рассмотрены во второй части. Штатный пакет Oracle DBMS_REDEFINITION предназначен для выполнения реорганизаций таблиц в БД с минимальным временем простоя. С помощью этого пакета можно, например, из несекционированной таблицы сделать секционированную. Основное достоинство этого пакета — операцию можно сделать в онлайн или с минимальной остановкой сервиса. Это не означает, что данный пакет использует какие то внутренние секретные инструкции, которые делают манипуляции в разы быстрее. Используется другой подход, суть которого заключается в том, что длительная по времени операция по реорганизации данных разделяется на несколько этапов. Важно правильно запланировать выполнение этих этапов, иначе никакого выигрыша в сокращении времени простоя не будет. Пакет хорошо документирован в официальной документации или, например, тут: https://oracle-base.com/articles/10g/online-table-redefinition-enhancements-10gr1  С помощью этого пакета реорганизация таблицы выполняется в несколько этапов: create table - cоздается новая целевая таблица с другим именем. EXEC DBMS_REDEFINITION.start_redef_table - инициируется процесс начала реорганизации таблицы. В этот момент создается MVIEW и MVIEW LOG для регистрации изменений в оригинальной таблице. EXEC DBMS_REDEFINITION.copy_table_dependents - инициируется копирование зависимостей исходной таблицы на целевую. EXEC DBMS_REDEFINITION.sync_interim_table - выполняется копирование данных оригинальной таблицы в целевую либо догрузка изменений, если запускать несколько раз. EXEC DBMS_REDEFINITION.finish_redef_table - выполняется финальная синхронизация изменений в целевую таблицу и выполняется переключение указателя на сегменты данных оригинальной таблицы на целевую. В результате оригинальная таблица получает имя новой, а новая получает имя оригинальной. Созданные временные объекты для поддержки синхронизации удаляются. Рассмотрим пример использования DBMS_REFEDINITION на примере: Оригинальный скрипт: Что с этим скриптом не так? Вроде бы вся последовательность использования процедур пакета DBMS_REDEFINTION выполнена? Тем не менее, скрипт отрабатывал 8 часов. Проведенный анализ показал, что операция переноса данных из оригинальной таблицы в целевую отработала быстро, в режиме распараллеливания DML, а затем последовало создание индексов, в один поток, и как раз это заняло все основное время: Добавление в скрипт команды включения параллельного DDL ускорило процесс, но общее время выполнения операции все равно было более 1ч. Что было сделано не правильно и как можно ускорить процесс? Исходя из указанного выше кода видно, что основное преимущество DBMS_REDEFINITION по сравнению с обычными последовательными командами создания таблицы, копирования данных и создания индексов не было использовано. Следовало разбить данный скрипт на 2 этапа. Первый — создание таблицы, копирование основного объема данных и создания индексов; синхронизации изменений таблицы, которые накопились за время создания индексов. Второй — остановка сервисов, финальное применение дельты изменений и завершение реорганизации таблицы. В этом случае на время простоя оказало бы влияние только длительность применения дельты изменений в оригинальной таблицы и оно бы составляло несколько минут. Таким образом, DBMS_REDEFINITION хорошо будет работать там, где длительную по времени задачу можно разбить на этапы подготовки и выполнения, согласно следующей схеме: К недостаткам пакета можно отнести тот факт, что нет возможности влиять на те операции, которые выполняются внутри при вызове процедур пакета. CTAS — Create Table As Select. Данный метод является самым быстрым решением задачи удаления большого объема данных из большой таблицы. Прямая (direct) загрузка данных в таблицу, не обремененной какими либо индексами, ограничениями целостности и тд, с последующим созданием индексов и ограничений целостности может отрабатывать гораздо быстрее, чем просто удаление данных большого объема данных из таблицы. При этом таблица и индексы оптимизируется, блоки данных заполняются полностью и последующие операции SELECT и DML будут работать быстрее. В случае с удалением, такой же эфект после DELETE достигается лишь с последующим MOVE таблицы и перестройки индексов. Рассмотрим пример с таблицей, в которой 148млн записей, есть составной уникальный индекс, включающий CALL_ID,  а задача — удалить половину записей до CALL_ID<20736627961. Первый вариант решения - в лоб. Просто удаляем данные: Второй вариант решения — метод CTAS, создание новой таблицы с переливкой в нее данных, которые требуется сохранить: Из сравнительного теста видно, что переливка 1/2 данных в новую таблицу с последующим созданием индекса оказалось на 1,5 минуты быстрее, чем удаление 1/2 данных из этой таблицы. При этом в первом случае размер таблицы и индекса не сократился, а во втором — стали в 2 раза меньше. Чтобы после DELETE сократить размер таблицы, потребуется дополнительно выполнить операторы ALTER TABLE.. MOVE и ALTER INDEX... REBUILD, направленные на уплотнение хранения записей в таблице и уменьшение ее размера. Таким образом, общее время варианта с DELETE еще более увеличится. В каждом конкретном случае с большими объектами стоит проводить тесты, но теперь вы знаете, что есть такой метод CTAS и он может быть быстрее чем DELETE. Не забудьте только переименовать новую таблицу). Upd: Начиная с версии 12.2 появилась возможность вместо традиционного DELETE + MOVE TABLE выполнить ALTER TABLE ... MOVE INCLUDING ROWS, т.е. выполнить перемещение таблицы только с определенными записями по условию:   Таким образом, расширенный синтаксис ALTER TABLE MOVE позволяет более удобно добится поставленной цели удаления большого объема данных, без создания промежуточной таблицы.   Пакет Oracle DBMS_PARALLEL_EXECUTE предназначен для реализации параллельной обработки больших объемов данных. С помощью пакета целевой объект делится на логические части (chunk) заданного размера, и далее каждая порция подается на вход обработчикам. Количество обработчиков настраивается. В качестве обработчика удобно использовать хранимую процедуру. Документация. О методе расскажу подробнее на реальном примере: В процессе сборки кумулятивного патча миграции с S.Q до версии X.Y столкнулись с долгим временем скриптов миграции данных stage 1 и 2. Время работы скриптов 1 и 6 часов соответственно. Неприемлемо!  Исходный скрипт миграции содержал PL/SQL блок. Внутри SELECT, который выбирает данные, подлежащие миграции, открывается цикл FOR rec in (SELECT...) LOOP... и далее выполняются UPDATE, INSERT,... Для применения решения потребовалось незначительное изменение исходного кода PL/SQL блока, а именно PL/SQL блок был оформлен в виде процедуры с двумя входными параметрами l_low_rid, i_high_rid с типом ROWID и добавления условия в WHERE rowid between start_id and end_id. Выполняется подготовка среды выполнения, создание задачи для PE: Выполняется нарезка порций: При вызове процедуры для нарезки порций указываться имя ранее созданной задачи (task_name), указывается имя владельца схемы и имя таблицы, данные в которой предполагается разбить равномерно. Значение параметра by_row => false определяет, что разбиение будет на основе числа блоков, а не строк в таблице. Целесообразнее делать именно поблочное разбиение, чтобы конкурентные сессии не конфликтовали между собой при обращении к одним и тем же блокам (в примере скрипте таблица CONTRACT также обновляется, поэтому это актуально. chunk_size — 10 000 блоков. В итоге получилось 206 частей. Пакет предлагает и другие способы нарезки на порции, например, вызов CREATE_CHUNKS_BY_NUMBER_COL позволяет поделить таблицу на порции на основе диапазонов числовых идентификаторов. Удобно, если в таблице хранятся строки с монотонно‑возрастающим идентификатором, без пропусков. Еще один вариант — процедура create_chunks_by_sql. Она позволяет выполнить разделение на порции на основе пользовательского запроса, который должен вернуть диапазоны ROWID или ID, если by_rowid => false. Результат «нарезки» можно посмотреть в представлении user_paralle_execute_chunks: В результате — выполнена нарезка на порции, у каждой порции есть начальный и конечный адрес строки ROWID. Статус UNASSIGNED означает, что chunk‑и не взяты в работу. Далее выполняется запуск. В коде указывается имя процедуры и параметры, определяющие обрабатываемую порцию за каждый вызов: В момент вызова run_task сессия создает джобы, каждый из которых будет обрабатывать свою порцию. Запуск джобов должен быть разрешен в БД. Инициирующая сессия подвисает на время выполнения — ожидает завершения обработки всех порций. Для наблюдения за прогрессом целесообразно использовать запрос из предыдущего блока, а также смотреть v$active_session_history или Oracle Enterprise Manager Top Activity за прогрессом и потенциальными проблемами/ конкруренцией.  Итого время на все сократилось в 4 раза с 1 часа до 15 минут! А время выполнения второго скрипта сократилось в 7 раз с 6 часов до 50 минут. Каждая порция обрабатывается в отдельной сессии. И если pl/sql блок не делает промежуточных commit, то смигрирует либо весь chunk либо ничего. Таким образом, может получится, что отдельные порции могут не смигрировать. В такой ситуации у несмигрировавших порций будет статус PROCESSED_WITH_ERROR. Как быть? Во‑первых, существует возможность повторно запустить обработку необработанных/ошибочных chunks. Для этого следует воспользоваться вызовом: Во‑вторых, в dba_parallel_execute_chunks есть поля ERROR_CODE, ERROR_MESSAGE. Тут будет код и текст той ошибки, которую поймает и выдаст исходный pl/sql блок. Так что можно разобраться, исправить и также запустить повторно. Разумеется, скрипт миграции должен быть «умным» и должен браться только за те данные, что еще не были смигрированы.  И еще. Может оказаться так (вернее, оказалось именно так со вторым скриптом миграции), что запрос, выбирающий данные, подлежащие миграции, довольно тяжелый. И если при последовательном выполнении pl/sql блока миграции в одном потоке он выполнялся долго 1 раз, то при новом подходе он будет выполняться число раз, равное числу порций. Решением может быть и стало вынос тяжелого подзапроса в отдельный скрипт, который создает временную таблицу и индекс. А дальше эти данные многократно используются конкурентными сессиями при обработке каждого chunk.  Конкурентные сессии будут обрабатывать разные данные, но в одних и тех же сегментах. Если есть insert, то скорее всего будет конкуренция за ITL слоты enq: TX — allocate ITL entry. Тут же возможна и ORA-00 060 deadlock detected. Причина — при обновлении блоков разными сессиями недостаточное число слотов для идентификатора транзакции. Если блок занят на 100%, новым слотам помимо изначально выделенных (задается в параметре таблицы/индекса initrans) расти некуда и сессия ожидает с указанным enqueue. Если случается что сессия S1 ждет блок b2, который был обновлен сессией S2, а та в свою очередь захотела обновить блок b1, то возникает ORA-00 060. Решение очень простое — перед запуском скрипта миграции выполнить ALTER TABLE MOVE / ALTER INDEX REBUILD с указанием большего числа INITRANS. Лучше, если это будет большее простое число.  Кроме того, может и возникнет ожидание buffer busy waits на таблицах и индексах. Тут можно посоветовать удалить ДО и создать ПОСЛЕ индексы, за исключением может быть PRIMARY KEY, который может понадобиться при миграции, а также увеличение freelists если используется MANUAL SPACE SEGMENT MANAGEMENT. 1. DBMS_PARALLEL_EXECUTE 2. Oracle Scratchpad  - Parallel Execution   Метод основан на разделении таблицы на диапазоны ID или диапазоны ROWID и генерации отдельных скриптов для обработки каждого диапазона. Обработка диапазонов или наборов диапазонов запускается параллельно в нескольких сеансах SQLPLUS. Ниже приводится пример оператора, который генерирует текст DML запроса для обновления таблицы CLIENT_HISTORY, разбивая его на несколько (10) потоков (stream) путем формирования диапазовнов ROWID на основе параметров физического хранения таблицы, числу блоков и файлов данных В результате получается следующий код: Операторы каждого из 10 потоков помещаются каждый в свой *.sql файл и запускаются одновременно, например, через sqlplus. 10 сессий, каждая отработает по 4 оператора и это будет значительно быстрее, если бы этот UPDATE работал в 1 поток. Данный метод хорошо подходит для Oracle SE2, в котором нет поддержки Parallel DML. Используя этот метод, задачу можно распараллелить. Удобство данного метода по сравнению с штатным пакетом DBMS_PARALLEL_EXECUTION еще и в том, что запуская задачу через sqlplus в несколько потоков, мы не зависим от джобов Oracle, которые обычно отключаются на время апгрейда. Создание ограничений целостности на большие таблицы может занимать длительное время, например создание внешнего ключа по SUBS_ID на таблице BIG_TABLE занимает 10 минут. Данную операцию можно ускорить: Ограничение целостности создалось и уже работает для всех новых транзакций, однако текущие данные еще не проверены. Далее следует сделать операцию VALIDATE. Первый вариант — запуск VALIDATE в режиме параллельного DDL: Ускорение почти в 10 раз, с 10 минут 8 секунд до 1минуты 10 секунд! Важно не забыть обнулить degree у таблицы, выполнив команду ALTER TABLE... NOPARALLEL; чтобы избежать нежелательных проблем в будущее. Второй вариант — текущие скрипты оставить как есть, а операцию VALIDATE для ограничения целостности вынести в отдельный скрипт, post patch. Подобные отложенные операции запускать уже после того как основное обновление на БД запущено, во время выполнения проверок, тестов и даже запуска сервисов. Операция будет выполняться примерно те же 10 минут, однако это время будет уже за пределами критического окна на выполнение работ по установке обновлений. Данный вариант очень хорошо подходит для Oracle Standard Edition 2, в котором параллельные операции DDL и DML не поддерживаются. По методам распараллеливания у меня все, но есть еще несколько моментов, которые могут оказать влияние на время установки патчей. Параметр позволяет минимизировать число операций ввода-вывода во время сканирования таблиц. Он определяет максимальное количество блоков, считываемых за одну операцию ввода-вывода во время последовательного сканирования. Для OLTP систем, с целью предпочтительного использования индексов, значение параметра может быть установлено в значения от 4 до 16 и поэтому, при выполнении массовых изменений данных или выполнения реорганизации объектов, стоит проверить установленное значение и выставить на уровне сессии в более подходящее. Максимальный размер операции ввода-вывода  зависит от ограничений операционной системы и в случае указания большего значения будет действовать максимально возможное. Почитать дополнительно. Очень часто в патчах приходится сталкиваться с тем, что в DDL командах используются операнды NOLOGGING. Да, данный операнд в ряде случаев позволяет уменьшить размер информации, записываемой в журналы транзакций Oracle Redo Logs, однако у всех наших заказчиков используется решение по отказоустойчивости — Standby Database, изменение в которую реплицируются как раз с помощью журналов транзакций. С целью исключения возможности не передачи на резервную БД каких‑либо изменений в основной и появлению факта рассихронизации при создании Disaster Recovery (DR) конфигурации на уровне БД включается режим FORCELOGGING и с этого момента указание NOLOGGING на отдельных операциях не имеет никакого смысла.  В тоже время, во время тестовых прогонов на стендах без DR конфигурации использование данного операнда может привести к искажению реальных временных характеристик, на тестовой БД за счет работы NOLOGGING операция может выполнится быстрее и будут получены заведомо ложные данные о времени установки обновления на БД. Рекомендуется НЕ использовать NOLOGGING в патчах, если у вас для резервирования на проде используется Standby Database Иногда встречаются ситуации, когда какой то объект может создаваться как в патче‑оперативном исправлении (ОИ) так и в релизном патче, предварительные условия установки которого не требуют установки оперативного патча. В результате при установке могут быть ошибки о том что объект уже существует и т.д, которые могут смущать неопытных администраторов, да и просто выглядит не очень красиво — патч устанавливается с ошибками. Пример: Индекс fact$main_fact_id$idx уже создавался в ОИ 1.3.29.7, но был также включен в релиз 1.3.30.0, который устанавливается на минимальную версию 1.3.29.5. Таким образом, при установке 1.3.30 индекс может отсутствовать или присутствовать. В последнем случае при попытке его создания будет ошибка: Решением может быть создание временной процедуры в начале установки патча, которая будет обрабатывать подобные такие ситуации: Конкретно эта процедура корректно отрабатывает исключительные ситуации : ORA-01918: user 'string' does not exist ORA-01543: tablespace 'string' already exists ORA-00955: name is already used by an existing object ORA-01921: role name 'string' conflicts with another user or role name ORA-01920: user name 'string' conflicts with another user or role name Пример использования процедуры: Аналогичным образом могут быть созданы процедуры silent_alter, silent_drop. В целях безопасности, в конце установки патча такие процедуры, если они были созданы, следует удалить!!! Важным этапом разработки патча является корректное журналирование выполняемых операторов DDL, DML, с фиксацией времени выполнения. И тут есть 2 важных момента: При множестве последовательных операторов DDL и DML и возникновении ошибки или обнаружения длительного времени выполнения операции может быть трудно найти этот конкретный оператор. Вариант включения SET ECHO ON не желателен, т.к. приведет к большому объему текста в логе и трудностям с его чтением и фильтрацией, например по ключевым словам ORA или ERROR. Оптимальный вариант — запись комментариев в журнал с помощью операнда PROMPT: Второй момент заключается в добавлении в патч установок для включения таймера, а также включение вывода в журнал времени выполнения каждой отдельной операции. В патчах, особенно кумулятивных, могут быть сотни и тысячи операторов и быстро выявить топ самых длительных довольно трудно. Рекомендуется делать промежуточный вывод времени текущего значения таймера, например после каждого отдельного блока установки патча — изменения схемы, запуска миграций данных и т. д. Такой подход позволит быстрее по журналам выявить наиболее долго‑выполняющиеся блоки и быстрее локализовать конкнетные операторы или PL/SQL блоки. Я перечислил основные методы, которые мы успешно применяем для минимизации времени простоя комплекса у наших Заказчиков. Изучайте, пробуйте и тестируйте и у Вас тоже получится сокращать начальное время установки патчей с 48-ми до 3-х часов. И помните, при использовании любых методов всегда важно проведение качественного тестирования на подходящем оборудовании, максимально схожим продуктивному настроенном окружении и на адекватных объемах данных. Спасибо, что дочитали этот длинный текст до конца. Со своей стороны постараюсь не затягивать с продолжением темы и во второй части расскажу о подходах к тестированию, мониторингу и диагностике проблем при установке патчей на тестовые и продуктивные БД размером в десятки и сотни ТБ.  Senior Oracle DBA