ADG Оставить заявку
Блог Данные и аналитика 5 мин чтения

Миграция с MS SQL на Postgres Pro: схема конвертации процедур и что показало нагрузочное тестирование

Первая крупная миграция с Microsoft SQL Server на Postgres Pro для производственного предприятия - разбираем конвертацию хранимых процедур и итоги нагрузки.

Контекст момента

Миграция с Microsoft SQL Server на отечественные СУБД становится обязательной для значимых объектов КИИ - методические рекомендации ФСТЭК

В январе ФСТЭК выпустил методические рекомендации, где прямо указал: Microsoft SQL Server на значимых объектах КИИ - это иностранное ПО, которое подлежит замене. Никаких исключений для «исторически сложившихся» инсталляций. Несколько наших клиентов это и без рекомендаций понимали, но бумага ускорила разговоры.

Одну такую миграцию - производственное предприятие, достаточно крупная БД с несколькими десятками хранимых процедур - мы завершили на прошлой неделе. Делимся схемой, которая у нас сложилась, и тем, что показал нагрузочный тест.

Почему MS SQL в Postgres Pro - это не просто «переключить строку подключения»

Это вопрос, который нам приходится объяснять на каждом первом разговоре с заказчиком. MS SQL и PostgreSQL - это два разных диалекта SQL с разной процедурной логикой, разными типами данных и принципиально другой архитектурой транзакций. Postgres Pro как дистрибутив поверх PostgreSQL эту проблему не снимает: он добавляет инструменты и поддержку, но не превращает T-SQL в PL/pgSQL автоматически.

Конкретные болевые точки, с которыми мы столкнулись:

  • Хранимые процедуры на T-SQL. В MS SQL процедуры пишутся на T-SQL со своими конструкциями: TOP, NOCOUNT, ISNULL, GETDATE(), курсоры со специфическим синтаксисом, временные таблицы через #temp. Всё это надо переписывать на PL/pgSQL вручную - автоматических конвертеров, которым можно доверять без проверки, нет.
  • Типы данных. DATETIME в MS SQL не эквивалентен timestamp в PostgreSQL по поведению с временными зонами. VARCHAR(MAX) превращается в TEXT. BIT с логикой 0/1/NULL требует проверки - в PostgreSQL BOOLEAN ведёт себя иначе в части NULL. MONEY - использовали NUMERIC(19,4).
  • Схема именования. MS SQL по умолчанию складывает объекты в dbo, PostgreSQL работает со своей системой схем. На практике это значит, что все ссылки на dbo.TableName надо приводить к правильному виду.
  • Транзакционная модель. MS SQL допускает DDL внутри транзакций с определёнными ограничениями; PostgreSQL тоже допускает, но поведение в edge cases отличается. Процедуры с BEGIN TRAN / COMMIT TRAN внутри требовали отдельного внимания.

Схема, которую мы использовали

Мы разбили работу на четыре этапа и шли строго последовательно - попытки совместить этапы на прошлых проектах приводили к тому, что исправления в схеме ломали уже переписанные процедуры.

Первое - аудит объектов. Полный список таблиц, представлений, хранимых процедур, триггеров, индексов, ограничений. Для каждой процедуры - количество строк кода, список T-SQL-конструкций, которые требуют ручной адаптации. Это позволяет реалистично оценить объём работы ещё до начала.

Второе - схема данных. Конвертация DDL: таблицы, типы, ограничения, индексы. Здесь помогает pgloader или ручной скрипт - зависит от сложности. Мы сделали полуавтоматически: pgloader для базовой структуры, ручная доработка для колонок с нестандартными типами и ограничениями. После - проверка на тестовом стенде с реальными данными.

Третье - хранимые процедуры. Конвертация вручную по каждой. Для данного клиента - несколько десятков процедур разной сложности. Простые (без курсоров, без временных таблиц, без вложенных транзакций) - переписываются быстро. Сложные - с курсорами и динамическим SQL - это отдельная история на несколько часов каждая.

Ключевые замены в коде:

  • ISNULL(x, y) -> COALESCE(x, y)
  • GETDATE() -> NOW() или CURRENT_TIMESTAMP
  • TOP N -> LIMIT N
  • SET NOCOUNT ON - убирается (в PostgreSQL нет аналога, это поведение по умолчанию)
  • Временные таблицы #temp -> TEMP TABLE в PostgreSQL или CTE где возможно
  • Курсоры - переписывали на FOR loops в PL/pgSQL либо на set-based запросы

Четвёртое - нагрузочное тестирование. После переноса данных и всех объектов - тест под реальной нагрузкой перед переключением.

Что показал нагрузочный тест

Тест делали в два прохода: синтетический (pgbench с кастомными сценариями, имитирующими типовые операции) и с реальными запросами из логов MS SQL за последний месяц.

Общий вывод такой: на OLTP-запросах - INSERT, простые SELECT по первичному ключу, обновления единичных строк - разница минимальна. Postgres Pro справляется на той же скорости или чуть быстрее.

На аналитических запросах - несколько JOIN-ов, агрегаты по большим таблицам - картина неоднородная. Часть запросов ускорилась за счёт лучшего планировщика PostgreSQL и параллельных запросов. Несколько запросов оказались заметно медленнее - выяснилось, что планировщик выбирал неоптимальный план из-за устаревшей статистики. После ANALYZE и добавления нескольких индексов, которых в MS SQL не было, ситуация выправилась.

Одна процедура в нагрузочном тесте упала с ошибкой - обнаружился edge case с NULL в булевом сравнении, который в T-SQL обрабатывался иначе. В продакшн не пошли до исправления. Это, собственно, и есть аргумент в пользу нагрузочного теста с реальными данными, а не только юнит-проверок процедур.

Что осталось за кадром

Это была база данных одной из подсистем предприятия - не основная производственная. Основная идёт следующим этапом, и там объём процедур и связанных приложений существенно больше. Плюс там есть интеграции с несколькими внешними системами через ODBC, которые тоже потребуют адаптации.

По срокам полного перехода мы сейчас говорим с клиентом откровенно: до дедлайна ФСТЭК в 2025 году успеть реально, но только если не останавливаться. Работа по интеграции и миграции такого масштаба не терпит пауз - каждый месяц простоя сжимает окно для нагрузочного тестирования и опытной эксплуатации.

Если у вас тоже есть MS SQL на КИИ-объекте и вы пока только «смотрите в сторону» миграции - лучший момент начать инвентаризацию был три месяца назад. Второй лучший момент - сейчас.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.