Xora AI Искусственный
интеллект
Проверить готовность
01ИИ-трансформация 02Направления 03Продукты 04Обучение 05Кейсы 06Блог 07Контакты
Проверить готовность

Импортозамещение

Миграция с Oracle и MS SQL на PostgreSQL: что ломается первым

Хранимые процедуры, специфичные типы, планы запросов, нагрузочные профили.

Что произошло

Уход Oracle и Microsoft с российского рынка перевёл миграцию СУБД из категории «когда-нибудь» в категорию «до конкретной даты». Для значимых объектов критической информационной инфраструктуры срок перехода на отечественные решения установлен — 1 января 2028 года. Для остальных компаний давление иное, но не слабее: продление лицензий невозможно, техническая поддержка недоступна, обновления безопасности не приходят, а любой сбой на неподдерживаемой версии — риск, который никто не хочет объяснять совету директоров.

PostgreSQL стал ответом по умолчанию: открытая лицензия, зрелая экосистема, отечественные сборки с сертификацией и поддержкой — Postgres Pro и его производные, Greenplum для аналитических нагрузок.

Проблема в том, что миграцию часто планируют как перенос данных: выгрузить таблицы, загрузить в новую базу, переключить строку подключения. На этой модели строится бюджет и сроки. А затем выясняется, что в базе Oracle живут тысячи хранимых процедур, десятки пакетов, триггеры на каждой второй таблице и задания планировщика, о которых не помнит никто из действующих сотрудников. Данные переезжают за выходные. Логика — за год.

Таблицы переносятся утилитой. Поведение системы — только руками.

Что ломается первым

Хранимый код: PL/SQL и T-SQL против PL/pgSQL

Корпоративные системы, построенные в 2000-х и 2010-х, часто держат бизнес-логику в базе данных. В результате миграция СУБД становится миграцией приложения.

PL/SQL и PL/pgSQL похожи синтаксически — PL/pgSQL проектировался с оглядкой на Oracle, — но различаются в ключевых механизмах. В PostgreSQL нет пакетов: код, организованный в пакеты с общим состоянием и приватными процедурами, приходится раскладывать по схемам и переписывать работу с переменными пакета. Нет автономных транзакций: процедура, которая в Oracle писала журнал независимо от основной транзакции, в PostgreSQL потребует другого механизма — например, отдельного соединения через расширение. Обработка исключений в PL/pgSQL создаёт точку сохранения на каждом блоке с обработчиком, и код, который в Oracle оборачивал каждую строку в цикле в свой обработчик, в PostgreSQL начинает заметно тормозить.

T-SQL отличается сильнее. Процедуры в SQL Server возвращают наборы строк напрямую — в PostgreSQL для этого нужны функции с возвратом таблицы или курсоры. Временные таблицы ведут себя иначе. Табличные переменные и табличные параметры не имеют прямого аналога. Кросс-базовые запросы вида база.схема.таблица не работают: в PostgreSQL база данных — граница, и обращение к другой базе требует расширения для внешних данных. Задания агента SQL Server, пакеты интеграции, сборки CLR — всё это существует вне языка и требует замены другими инструментами.

Автоматические конвертеры — ora2pg и аналоги — переводят синтаксис, но не семантику. Они справляются с простыми процедурами и оставляют на ручную доработку всё, что использует специфические механизмы. По нашему опыту проектов конвертер закрывает основную массу строк кода, но ключевые процедуры — те самые, на которых держится расчёт, — переписываются вручную, и именно они определяют срок.

Типы данных и тихие расхождения

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

В Oracle пустая строка и NULL — одно и то же. В PostgreSQL это разные значения. Условие «поле не равно пустой строке» ведёт себя по-разному, конкатенация с NULL даёт NULL, и процедура, которая в Oracle десятилетиями собирала адрес из нескольких полей, в PostgreSQL начинает возвращать пустой адрес, если хотя бы одно поле не заполнено.

Тип DATE в Oracle содержит время. В PostgreSQL DATE — только дата, и сравнение, которое в Oracle отсекало записи по времени внутри дня, после миграции ведёт себя иначе. Тип NUMBER без указания точности хранит то, что в него записали; аналог в PostgreSQL — numeric — тоже, но арифметика с делением даёт разное количество знаков после запятой, и суммы в отчётах расходятся на копейки, что для бухгалтерии равносильно неверному отчёту.

Идентификаторы без кавычек Oracle приводит к верхнему регистру, PostgreSQL — к нижнему. Если в приложении хоть где-то имя таблицы взято в кавычки, после миграции оно перестаёт находиться. В SQL Server сравнение строк по умолчанию нечувствительно к регистру — в PostgreSQL чувствительно, и поиск по фамилии, введённой строчными буквами, перестаёт находить записи.

Неявные преобразования типов в PostgreSQL строже: запрос, который в Oracle сравнивал число со строкой, здесь завершится ошибкой. Это как раз тот случай, когда ошибка лучше тихого расхождения.

Планы запросов и индексы

Один и тот же SQL-запрос в разных СУБД выполняется по разным планам, потому что оптимизаторы устроены по-разному и собирают разную статистику. Запрос, который в Oracle выполнялся за миллисекунды благодаря подсказке оптимизатору, в PostgreSQL подсказку проигнорирует — их в базовой поставке нет, есть только расширение — и выберет план, который на объёме промышленной базы работает минуты.

Индексы переносятся не один в один. Кластерные индексы SQL Server, которые определяют физический порядок строк, в PostgreSQL отсутствуют как постоянная структура. Битовые индексы Oracle для аналитических запросов заменяются другими типами. Зато у PostgreSQL есть частичные индексы, индексы по выражениям, GIN и BRIN — которыми можно закрыть те же задачи, но их надо проектировать заново под фактические запросы, а не копировать список индексов из старой базы.

Отдельная тема — многоверсионность. Oracle хранит старые версии строк в отдельном сегменте отката, PostgreSQL — прямо в таблице, и они удаляются процессом очистки. Нагрузка с частыми обновлениями одних и тех же строк, которая в Oracle работала стабильно, в PostgreSQL без правильной настройки автоочистки приводит к разбуханию таблиц и деградации со временем — через недели, а не сразу.

Нагрузочный профиль и соединения

Модель соединений различается принципиально. PostgreSQL создаёт отдельный процесс на каждое соединение; приложение, которое привыкло держать открытыми тысячи соединений к Oracle, положит PostgreSQL по памяти. Между приложением и базой нужен пул соединений, и его настройка — отдельная задача, которая влияет на поведение транзакций и подготовленных запросов.

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

Механизм Oracle / MS SQL PostgreSQL Что ломается
Пакеты и состояние сессии Пакеты PL/SQL Нет пакетов; схемы и функции Переменные пакета, приватные процедуры
Автономные транзакции Есть Нет в базовой поставке Журналирование внутри транзакции
Пустая строка Равна NULL (Oracle) Отлична от NULL Условия и конкатенация
Регистр идентификаторов Верхний Нижний Имена в кавычках
Сравнение строк Нечувствительно (MS SQL) Чувствительно Поиск и уникальность
Подсказки оптимизатору Есть Только через расширение Планы тяжёлых запросов
Кросс-базовые запросы база.схема.таблица Внешние данные через расширение Интеграционные процедуры
Соединения Потоки, тысячи соединений Процесс на соединение Память; нужен пул
Старые версии строк Сегмент отката В таблице; нужна очистка Разбухание при частых обновлениях

Как это выглядит на практике

Банк из первой сотни, учётная система на Oracle. Инвентаризация показала несколько тысяч объектов хранимого кода, из которых значительная часть не вызывалась ни разу за последний год — их исключили из переноса. Оставшиеся разделили на три слоя: справочники и простые процедуры перевели конвертером и проверили автоматической сверкой результатов; расчётные процедуры переписали вручную с параллельным прогоном на обеих базах; интеграционные процедуры заменили на обмен через шину. Данные переносились последними и заняли меньше всего времени. Основной срок ушёл на расчётный слой и на сверку: расхождения в округлении находились неделями.

Производственная компания, система планирования на SQL Server. Логика была размазана между процедурами, заданиями агента и пакетами интеграции. Пришлось сначала вытащить её в отдельный сервис приложений, а уже потом менять базу. Проект занял заметно больше времени, чем планировалось, — но в результате логика оказалась в коде, покрытом тестами, а не в базе.

Сеть розничных магазинов, отчётная витрина. Аналитическую нагрузку перенесли не на обычный PostgreSQL, а на Greenplum — массивно-параллельную СУБД на основе PostgreSQL. Транзакционные системы остались на Postgres Pro. Разделение нагрузок по разным движкам дало больше, чем попытка настроить одну базу под оба профиля.

Что это значит для российской компании

Регуляторика. Для субъектов КИИ дата перехода известна и не сдвигается, что превращает миграцию в проект с жёстким дедлайном. Планировать его с расчётом на «успеем за полгода до срока» опасно: сроки миграции хранимого кода прогнозируются плохо, а последние месяцы перед датой будут перегружены у всех подрядчиков рынка одновременно.

Отечественный стек. Postgres Pro в сертифицированных редакциях закрывает требования по реестру и сертификации, а также добавляет ряд механизмов, упрощающих перенос с Oracle. Greenplum и его отечественные сборки — вариант для аналитических хранилищ. Выбор между ванильным PostgreSQL и коммерческой сборкой — вопрос требований к поддержке и сертификации, а не производительности.

Кадры. Администраторы Oracle с двадцатилетним стажем не становятся администраторами PostgreSQL за неделю. Настройка очистки, пула соединений, репликации, резервного копирования — другая школа. Разработчики, писавшие PL/SQL, переучиваются быстрее, но нуждаются в ревью со стороны тех, кто знает подводные камни PL/pgSQL. Закладывайте обучение и внешнюю экспертизу на первые месяцы эксплуатации, а не только на миграцию.

Закрытый контур. Промышленные данные не покидают периметр: стенды разворачиваются на своей инфраструктуре, сверка выполняется на обезличенных копиях, если этого требует 152-ФЗ. Это удлиняет подготовку, но исключает вопросы при аудите.

Что делать: пошагово

  1. Инвентаризируйте хранимый код и зависимости. Все процедуры, функции, пакеты, триггеры, представления, задания планировщика, связанные серверы. Для каждого — частота вызова за год, вызывающие приложения, авторы. Объекты без вызовов исключаются из переноса, но фиксируются.
  2. Разделите код на слои по сложности и критичности. Справочные и простые процедуры — на автоматическую конвертацию. Расчётные — на ручной перенос. Интеграционные — на замену другим механизмом. У каждого слоя свой срок и свой критерий приёмки.
  3. Выберите целевую платформу под каждый профиль нагрузки. Транзакционные системы — PostgreSQL или Postgres Pro, аналитика — Greenplum или колоночные расширения. Не пытайтесь заставить один экземпляр обслуживать оба профиля.
  4. Постройте автоматическую сверку. Для каждой переносимой процедуры — набор входных данных и эталонный результат со старой базы; после переноса результаты сравниваются автоматически. Расхождения в округлении, порядке строк и обработке NULL ищутся именно так, а не ревью кода.
  5. Проведите нагрузочное тестирование на полном объёме данных. Реальный сценарий: транзакционный день, ночная загрузка, отчётность закрытия периода. Соберите планы тяжёлых запросов, спроектируйте индексы под них, настройте автоочистку и пул соединений.
  6. Переносите слоями с параллельной эксплуатацией. Сначала справочные подсистемы, затем расчётные, интеграционные — последними. На каждом слое старая и новая базы работают параллельно, результаты сверяются на живых данных до тех пор, пока расхождений нет.
  7. Подготовьте эксплуатацию заранее. Регламенты резервного копирования, мониторинга, репликации, обновления версий. Обучите администраторов до переключения, а не после.
  8. Зафиксируйте точку отката и переключайтесь. До момента отключения старой базы должна существовать проверенная процедура возврата. Старую базу отключайте только после закрытия хотя бы одного отчётного периода на новой.

Типичные ошибки

  • Оценивать проект по объёму данных. Почему: терабайты переносятся утилитой, а срок определяется числом и сложностью процедур. Что вместо: оценка по инвентаризации хранимого кода с разбивкой по слоям.
  • Доверять автоматической конвертации без сверки. Почему: конвертер переводит синтаксис, а расхождения в семантике — NULL, регистр, округление — обнаруживаются только сравнением результатов. Что вместо: автоматическая сверка на эталонных наборах для каждой процедуры.
  • Копировать индексы из старой базы. Почему: оптимизаторы разные, и старый набор индексов в PostgreSQL часто бесполезен или вреден. Что вместо: проектирование индексов по планам реальных запросов на полном объёме.
  • Тестировать нагрузку на выборке. Почему: планы запросов и поведение очистки на малом объёме не воспроизводят промышленных. Что вместо: тест на полной копии с реальным сценарием, включая закрытие периода.
  • Переключаться одним днём. Почему: при обнаружении расхождений после переключения откат дорог, а сверка на живых данных невозможна. Что вместо: параллельная эксплуатация по слоям с автоматической сверкой.

Как понять, что вы на верном пути

  • У вас есть реестр всех объектов хранимого кода с частотой вызовов и владельцами, и он был готов до того, как вы назвали срок проекта.
  • Для каждой переносимой процедуры существует эталонный набор данных и результатов, и сверка выполняется автоматически.
  • Нагрузочное тестирование проведено на полном объёме данных, планы тяжёлых запросов собраны и индексы спроектированы под них.
  • Старая и новая базы работали параллельно хотя бы на одном слое, и расхождения на живых данных доведены до нуля.
  • Администраторы прошли обучение по эксплуатации PostgreSQL до переключения, и регламенты резервного копирования и мониторинга написаны под новую платформу.
  • Процедура отката проверена на стенде, и решение об отключении старой базы принято после закрытия отчётного периода.

Вопросы, которые нам задают

Стоит ли переносить логику из базы в приложение по ходу миграции? Если хранимый код в любом случае переписывается вручную, вынос его в сервис приложений часто оправдан: логика становится тестируемой и независимой от СУБД. Но это удлиняет проект и меняет его характер. Решение принимается по слоям: расчётный слой, который переписывается целиком, — кандидат на вынос; справочный, который переносится конвертером, — нет.

Postgres Pro или ванильный PostgreSQL? Если нужны сертификация, вендорская поддержка с гарантированным временем реакции и средства, упрощающие перенос с Oracle, — коммерческая сборка. Если у вас сильная команда эксплуатации и нет требований по сертификации — ванильный PostgreSQL достаточен. Производительность и совместимость с приложениями в обоих случаях сопоставимы.

Сколько это занимает? Для системы с сотнями процедур и без экзотических механизмов — от нескольких кварталов до года с учётом параллельной эксплуатации. Для систем с тысячами объектов и логикой в пакетах — дольше, и точный срок появляется только после инвентаризации. Любая оценка, названная до инвентаризации, — предположение.

Первый шаг не требует бюджета: выгрузите список всех хранимых процедур, функций, триггеров и заданий планировщика из промышленной базы вместе с датой последнего вызова. Число объектов, которые вызывались за последний год, и есть реальный размер вашего проекта — независимо от того, сколько терабайт лежит в таблицах.

Вывод

Миграция СУБД — проект по переписыванию логики, а не по переносу данных.

По теме

Ещё о том же

Проверка готовности

Проверьте, готова ли ваша компания к AI

15 вопросов, 4 минуты. На выходе — где главное ограничение, какие AI-сценарии реалистичны, какой эффект можно ожидать и что закрыть в первую очередь.