Миграция с 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требует проверки - в PostgreSQLBOOLEANведёт себя иначе в части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_TIMESTAMPTOP N->LIMIT NSET NOCOUNT ON- убирается (в PostgreSQL нет аналога, это поведение по умолчанию)- Временные таблицы
#temp->TEMP TABLEв PostgreSQL или CTE где возможно - Курсоры - переписывали на
FORloops в 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 на КИИ-объекте и вы пока только «смотрите в сторону» миграции - лучший момент начать инвентаризацию был три месяца назад. Второй лучший момент - сейчас.