Источник изображения обложки: Source
Миграция данных и приложений с одной базы данных на другую — это задача, которая возникает довольно часто в процессе оптимизации работы IT-инфраструктуры. Сегодня мы поговорим о миграции с Microsoft SQL Server (MSSQL) на PostgreSQL, популярную открыто-исходную реляционную базу данных. Процесс миграции может быть сложным, но с правильным подходом его можно упростить и эффективно выполнить.
В этой статье мы рассмотрим основные этапы миграции и проблемы, с которыми вы можете столкнуться.
Зачем мигрировать с MSSQL на PostgreSQL?
Перед тем как перейти к процессу миграции, важно понять, почему стоит это сделать. Рассмотрим, зачем компании принимают такое решение, основные причины, плюсы и минусы этого процесса.
Основные причины для миграции
- Снижение затрат. PostgreSQL — это полностью бесплатная и открытая СУБД, распространяемая под лицензией PostgreSQL. В отличие от MSSQL, который требует оплаты лицензий (как на использование, так и на масштабирование), PostgreSQL позволяет значительно сократить затраты на эксплуатацию.
- Открытый исходный код. PostgreSQL — это open-source проект с большим сообществом разработчиков. Это даёт пользователям доступ к исходному коду, что открывает широкие возможности для кастомизации и интеграции с другими решениями.
- Кроссплатформенность. PostgreSQL работает на различных операционных системах, включая Linux, Windows и macOS. Это делает её более гибкой для компаний, которые используют разнородные технологические стеки.
- Широкий функционал. PostgreSQL предлагает мощные функции, такие как поддержка JSON/JSONB, сложные типы данных, расширяемость за счёт пользовательских функций и модулей, а также надёжные механизмы репликации и масштабирования.
- Соответствие стандартам. PostgreSQL является одной из самых стандартизированных СУБД (SQL:2011). Это упрощает миграцию и делает базу данных более универсальной для работы с различными системами.
Плюсы PostgreSQL
Критерий | Описание |
---|---|
Экономическая выгода | Отсутствие затрат на лицензирование. Бесплатные обновления и поддержка сообщества. |
Гибкость | Поддержка различных форматов данных. Возможность создания пользовательских расширений. |
Высокая производительность | Отлично справляется с большими объёмами данных. Эффективная работа с параллельными запросами. |
Безопасность | Расширенные механизмы аутентификации и шифрования. Поддержка управления доступом на уровне строк (Row-Level Security). |
Активное сообщество | Быстрая реакция на уязвимости. Большое количество готовых решений и документации. |
Минусы PostgreSQL
Критерий | Описание |
---|---|
Кривая обучения | Для специалистов, привыкших к MSSQL, потребуется время на изучение особенностей PostgreSQL |
Миграция данных | Процесс переноса базы данных может быть трудоёмким, особенно для сложных схем с использованием специфичных функций MSSQL. |
Отсутствие некоторых функций | MSSQL имеет встроенные инструменты, такие как SSRS (SQL Server Reporting Services) и SSAS (SQL Server Analysis Services), которые нужно заменить сторонними решениями при переходе. |
Поддержка крупных вендоров | PostgreSQL не предлагает коммерческую поддержку “из коробки”, как это делает Microsoft, хотя есть компании, предоставляющие такие услуги. |
Кому подойдёт миграция?
Переход с MSSQL на PostgreSQL особенно актуален для:
- Стартапов и малых бизнесов, которые хотят минимизировать затраты на инфраструктуру.
- Компаний, стремящихся к независимости от крупных вендоров.
- Организаций, работающих с большими объёмами данных или сложными типами данных.
- IT-команд, готовых инвестировать время в настройку и оптимизацию новой СУБД.
Этапы миграции
Этап 1. Анализ текущей базы данных
Перед началом миграции необходимо:
- Провести инвентаризацию всех объектов базы данных, включая таблицы, индексы, хранимые процедуры и триггеры.
- Оцените, сколько данных необходимо перенести, и подготовьтесь к возможным ограничениям производительности.
- Проверить совместимость типов данных и функций.
Сложные элементыХранимые процедуры, функции и специфичные для MSSQL конструкции требуют ручной доработки.
Этап 2. Подготовка к миграции
Этап 3. Создание схемы базы данных в PostgreSQL
- Переведите структуру таблиц из MSSQL в PostgreSQL, учитывая различия в синтаксисе (описаны ниже).
- Адаптируйте индексы, ограничения и связи.
Этап 4. Перенос данных
- Экспортируйте данные из MSSQL в формат, совместимый с PostgreSQL (например, CSV).
- Загрузите данные в PostgreSQL, используя утилиты вроде
COPY
или инструменты миграции. - Убедитесь, что данные корректно перенесены, проведя выборочную проверку.
Этап 5. Адаптация SQL-запросов и бизнес-логики
- Измените хранимые процедуры, триггеры и представления для работы с PostgreSQL.
- Перепишите специфичные запросы с учетом различий в синтаксисе.
Этап 6. Тестирование и оптимизация
- Проведите функциональное и нагрузочное тестирование на новой базе данных.
- Оптимизируйте запросы и настройте параметры PostgreSQL для достижения высокой производительности.
Этап 7. Переход на новую базу данных
- Перенаправьте приложение на использование PostgreSQL.
- Оставьте резервную копию MSSQL на случай необходимости отката.
Различия в синтаксисе MSSQL и PostgreSQL
Типы данных
NVARCHAR, VARCHAR(MAX), TEXT
MSSQL | PostgreSQL |
---|---|
NVARCHAR, VARCHAR(MAX), TEXT | TEXT или VARCHAR |
Основное отличие заключается в том, что PostgreSQL более универсально работает с TEXT, который не имеет ограничений по длине, в то время как в MSSQL для этого используется VARCHAR(MAX). NVARCHAR в MSSQL предназначен для хранения Unicode-данных, но в PostgreSQL поддержка Unicode реализована по умолчанию для всех строковых типов, поэтому нет необходимости использовать отдельный тип для этого.
DATETIME
MSSQL | PostgreSQL |
---|---|
DATETIME | TIMESTAMP |
В MSSQL тип данных DATETIME используется для хранения даты и времени. Однако в PostgreSQL аналогом для этого типа является TIMESTAMP. Основное отличие между ними состоит в уровне детализации и поддержке временных зон. В PostgreSQL есть два варианта TIMESTAMP:
- TIMESTAMP WITHOUT TIME ZONE: используется для хранения даты и времени без учета часового пояса.
- TIMESTAMP WITH TIME ZONE: позволяет учитывать часовые пояса, что может быть полезно в международных приложениях.
ВниманиеПри миграции следует быть внимательным, чтобы убедиться, что временные зоны корректно обработаны, если они важны для вашего приложения.
MONEY
MSSQL | PostgreSQL |
---|---|
MONEY | NUMERIC |
В MSSQL тип данных MONEY используется для хранения денежных значений. Однако, в PostgreSQL его аналогом является NUMERIC, поскольку он обеспечивает более гибкое и точное представление чисел с плавающей точкой.
Почему не MONEY в PostgreSQL?В PostgreSQL тоже есть тип MONEY, но его использование не рекомендуется, так как он менее универсален и сложнее в обработке для математических операций, чем NUMERIC.
NUMERIC позволяет точно задавать количество цифр до и после запятой, что полезно для финансовых операций, где критична точность.
Пример конверсии:
- MSSQL:
CREATE TABLE transactions (
amount MONEY
);
- PostgreSQL:
CREATE TABLE transactions (
amount NUMERIC(15, 2) -- 15 цифр, из которых 2 после запятой
);
UNIQUEIDENTIFIER
MSSQL | PostgreSQL |
---|---|
UNIQUEIDENTIFIER | UUID |
В MSSQL тип данных UNIQUEIDENTIFIER используется для хранения глобально уникальных идентификаторов (GUID). Его аналог в PostgreSQL — тип UUID, который также предназначен для работы с уникальными идентификаторами.
Ключевые моментыФормат: Оба типа представляют GUID в текстовом формате, например: 550e8400-e29b-41d4-a716-446655440000.
Генерация значений: - В MSSQL можно использовать функцию
NEWID()
для генерации GUID. - В PostgreSQL есть функцияgen_random_uuid()
(при наличии расширения pgcrypto) для генерации UUID.Использование: Они обычно применяются для идентификации строк в распределенных системах, где необходимо уникальное значение, не зависящее от сервера.
BIT
MSSQL | PostgreSQL |
---|---|
BIT | BOOLEAN |
В MSSQL тип данных BIT используется для представления логических значений, где 0 означает FALSE, а 1 — TRUE. В PostgreSQL для этого используется тип данных BOOLEAN, который является более естественным для работы с булевыми значениями.
ОсобенностиВ PostgreSQL значения BOOLEAN представляются словами: TRUE, FALSE и NULL (если отсутствует значение).
При миграции данные типа BIT автоматически преобразуются в BOOLEAN, но в SQL-запросах стоит заменить числа 0 и 1 на соответствующие булевы значения.
Пример конверсии:
- MSSQL:
CREATE TABLE example (
is_active BIT
);
INSERT INTO example (is_active) VALUES (1), (0);
- PostgreSQL:
CREATE TABLE example (
is_active BOOLEAN
);
INSERT INTO example (is_active) VALUES (TRUE), (FALSE);
Сопоставление типов
Чтобы не растягивать статью, ниже приведу таблицу сопоставления типов данных.
MSSQL | PostgreSQL |
---|---|
BIGINT | BIGINT, INT8 |
BINARY(n) | BYTEA |
VARBINARY(n) | BYTEA |
VARBINARY(max) | BYTEA |
ROWVERSION | BYTEA |
IMAGE | BYTEA |
FIELDHIERARCHYID | BYTEA, LTREE (расширение) |
BIT | BOOLEAN, BOOL |
CHAR(n), n<=8000 | TEXT |
NCHAR(n), n<=4000 | TEXT |
VARCHAR(n), n<=8000 | TEXT |
NVARCHAR(n), n<=4000 | TEXT |
VARCHAR(max) | TEXT |
NVARCHAR(max) | TEXT |
TEXT | TEXT |
NTEXT | TEXT |
FLOAT(n) | DOUBLE PRECISION, FLOAT8 |
SMALLMONEY | NUMERIC, MONEY |
MONEY | NUMERIC, MONEY |
INT, INTEGER | INT, INTEGER, INT4 |
SMALLINT | SMALLINT, INT2 |
NUMERIC(n,m) | NUMERIC(n,m) |
DEC(n,m), DECIMAL(n,m) | DEC(n,m), DECIMAL(n,m) |
TINYINT | SMALLINT, INT2 |
REAL | REAL, FLOAT4 |
UNIQUEIDENTIFIER | UUID, CHAR(16) |
DATE | DATE |
TIME(n) | TIME(n) |
DATETIME | TIMESTAMP(3) |
DATETIME2(n) | TIMESTAMP(m) |
DATETIMEOFFSET(n) | TIMESTAMP(n) WITH TIME ZONE, TIMESTAMPTZ |
SMALLDATETIME | TIMESTAMP(0) |
XML | XML |
ПримечаниеТипы CHAR и VARCHAR лучше не использовать. Причины подробно описаны здесь.
Более подробно о типах данных
Работа с идентификаторами
В MSSQL идентификаторы оборачиваются в квадратные скобки [column_name]
. Это полезно, если имя содержит пробелы или специальные символы. В PostgreSQL вместо этого используются двойные кавычки: "column_name"
. PostgreSQL чувствителен к регистру идентификаторов, если они заключены в кавычки.
MSSQL по умолчанию регистронезависим, даже если идентификаторы заключены в скобки. PostgreSQL чувствителен к регистру только тогда, когда идентификатор заключен в двойные кавычки. Например:
SELECT "Column_Name" FROM table_name;
В этом случае "Column_Name"
и column_name
будут считаться разными именами.
Практическое значениеПри миграции из MSSQL нужно убедиться, что имена объектов корректно адаптированы к правилам PostgreSQL. Если в MSSQL использовались скобки, их необходимо заменить на кавычки.
Также важно унифицировать регистр имен (обычно используются строчные буквы в PostgreSQL) во избежание путаницы.
Автоинкремент
Рассмотрим как в MSSQL и PostgreSQL реализуется автоматическая генерация значений для первичных ключей или других колонок, которые требуют последовательного увеличения (автоинкремент).
- В MSSQL для автоинкремента используется
IDENTITY
:
CREATE TABLE example (
id INT IDENTITY(1,1), -- '1,1' означает, что автоинкремент начинается с 1 и увеличивается на 1
name NVARCHAR(100)
);
ОсобенностиЗначение автоматически генерируется при вставке новых записей.
IDENTITY
жестко связан с колонкой, и его поведение нельзя напрямую изменить без пересоздания таблицы.
- В PostgreSQL используется
SERIAL
илиGENERATED
:SERIAL
— удобный синтаксический сахар для автоматической генерации последовательности.GENERATED ALWAYS AS IDENTITY
— современный стандарт SQL.
Пример с SERIAL
:
CREATE TABLE example (
id SERIAL, -- создается последовательность, связанная с колонкой
name VARCHAR(100)
);
Пример с GENERATED
:
CREATE TABLE example (
id INT GENERATED ALWAYS AS IDENTITY,
name VARCHAR(100)
);
Различия:
Гибкость:
- В PostgreSQL последовательности, созданные с
SERIAL
, можно явно изменять или использовать в других контекстах. IDENTITY
в MSSQL менее гибкий.
- В PostgreSQL последовательности, созданные с
Совместимость:
SERIAL
проще использовать для быстрого создания автоинкрементных колонок.GENERATED
рекомендуется для проектов, где важна поддержка современных стандартов SQL.
Миграция:
- При переносе таблиц из MSSQL в PostgreSQL, строки с
IDENTITY
обычно преобразуются вSERIAL
илиGENERATED
.
- При переносе таблиц из MSSQL в PostgreSQL, строки с
LIMIT и OFFSET
В MSSQL для этого есть два ключевых подхода:
TOP
: Используется для ограничения числа строк.
SELECT TOP 10 * FROM table_name;
OFFSET FETCH
: Этот метод позволяет пропустить определенное количество строк и взять фиксированное количество следующих.
SELECT *
FROM table_name
ORDER BY column_name
OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY;
В PostgreSQL для тех же целей используются LIMIT и OFFSET:
LIMIT
: Указывает максимальное количество строк, которые нужно вернуть.
SELECT * FROM table_name LIMIT 10;
OFFSET
: Указывает, сколько строк нужно пропустить перед возвратом результата.
SELECT *
FROM table_name
ORDER BY column_name
OFFSET 5 LIMIT 10;
Различия:
- MSSQL требует обязательного использования
ORDER BY
сOFFSET FETCH
, чтобы результат был предсказуемо упорядочен. - PostgreSQL не требует
ORDER BY
дляLIMIT
иOFFSET
, но его использование рекомендуется для получения детерминированного результата. - PostgreSQL имеет более простой и интуитивно понятный синтаксис.
Объединение строк
В MSSQL для объединения строк используется оператор +
.
SELECT first_name + ' ' + last_name AS full_name FROM users;
ОсобенностиЕсли один из объединяемых элементов равен NULL, весь результат становится NULL. Чтобы избежать этого, можно использовать функцию
ISNULL
:SELECT ISNULL(first_name, '') + ' ' + ISNULL(last_name, '') AS full_name FROM users;
В PostgreSQL для объединения строк используется оператор ||
.
SELECT first_name || ' ' || last_name AS full_name FROM users;
ОсобенностиЕсли один из объединяемых элементов равен NULL, весь результат становится NULL. Чтобы избежать этого, можно использовать функцию
COALESCE
:SELECT COALESCE(first_name, '') || ' ' || COALESCE(last_name, '') AS full_name FROM users;
Приведение типовВ PostgreSQL перед объединением может потребоваться явное приведение типов числовых данных к строковым с помощью функции
CAST
или::TEXT
.
Пустые строки и NULL
В PostgreSQL пустая строка (”) и NULL различаются, тогда как в MSSQL они могут трактоваться одинаково в некоторых случаях. Это связано с особенностями настроек совместимости или функций, таких как ISNULL
, которые позволяют заменить NULL значением по умолчанию.
В PostgreSQL пустая строка (”) и NULL считаются абсолютно разными понятиями:
- ” — это строка длиной 0, то есть пустая, но существующая.
- NULL — это отсутствие значения.
Это различие особенно важно при сравнениях. Например:
SELECT '' IS NULL; -- вернет FALSE
SELECT NULL IS NULL; -- вернет TRUE
Почему это важно при миграции
Обработка данных:
- Если в MSSQL колонка содержит пустые строки вместо NULL, то при переносе в PostgreSQL это может вызвать логические ошибки, особенно если приложение ожидает NULL.
Запросы:
- SQL-запросы, которые используют условия вроде
WHERE column IS NULL
, могут возвращать разные результаты, если значения из MSSQL были пустыми строками.
Исправление данных:
- При миграции данных важно привести к единому стандарту: либо заменить пустые строки на NULL, либо наоборот.
Как решить
- Перед миграцией данных можно заменить пустые строки на NULL в MSSQL:
UPDATE table_name
SET column_name = NULL
WHERE column_name = '';
- В PostgreSQL можно использовать функцию
COALESCE
для замены NULL на пустую строку (или наоборот) при выполнении запросов:
SELECT COALESCE(column_name, '') AS result FROM table_name;
Работа с датами
В MSSQL для получения текущего времени используется функция GETDATE()
. Эта функция возвращает дату и время в формате DATETIME, включающем год, месяц, день, часы, минуты, секунды и доли секунды.
В PostgreSQL используется функция CURRENT_TIMESTAMP
. Она возвращает аналогичный результат, включающий дату и время, но в формате TIMESTAMP WITH TIME ZONE (если не указанно иначе).
Различия в форматах и функциях:
Тип данных:
- В MSSQL типы DATETIME и SMALLDATETIME представляют дату и время, но они имеют разную точность и диапазон.
- В PostgreSQL используется TIMESTAMP (без часового пояса) и TIMESTAMP WITH TIME ZONE, что позволяет явно учитывать часовые пояса.
Функции преобразования:
- В MSSQL для приведения даты к строке используется
CONVERT
:
SELECT CONVERT(VARCHAR, GETDATE(), 101); -- MM/DD/YYYY
- В PostgreSQL используется функция
TO_CHAR
:
SELECT TO_CHAR(CURRENT_TIMESTAMP, 'MM/DD/YYYY');
- В MSSQL для приведения даты к строке используется
Сравнение и операции с датами:
Добавление или вычитание дат:
- В MSSQL используется функция
DATEADD
:
SELECT DATEADD(DAY, 7, GETDATE()); -- Добавить 7 дней
- В PostgreSQL используется сложение с интервалами:
SELECT CURRENT_TIMESTAMP + INTERVAL '7 days';
- В MSSQL используется функция
Разница между датами:
- В MSSQL используется
DATEDIFF
:
SELECT DATEDIFF(DAY, '2023-12-01', '2023-12-31');
- В PostgreSQL это выполняется простым вычитанием:
SELECT '2023-12-31'::DATE - '2023-12-01'::DATE;
- В MSSQL используется
МиграцияЕсли в MSSQL используется DATETIME, его нужно преобразовать в TIMESTAMP PostgreSQL.
Нужно учитывать, поддерживает ли приложение работу с часовыми поясами, так как PostgreSQL различает TIMESTAMP и TIMESTAMP WITH TIME ZONE.
Хранимые процедуры и функции
В MSSQL хранимые процедуры (stored procedures) создаются с помощью ключевого слова CREATE PROCEDURE
. Они используются для выполнения набора SQL-запросов с возможностью передачи параметров. Результаты можно возвращать через параметры или использовать в SQL-запросах.
CREATE PROCEDURE example_procedure
@param1 INT,
@param2 NVARCHAR(50)
AS
BEGIN
INSERT INTO table_name (column1, column2)
VALUES (@param1, @param2);
END;
Вызов:
EXEC example_procedure 10, 'Sample Text';
В PostgreSQL вместо хранимых процедур чаще используются функции. Они создаются с помощью ключевого слова CREATE FUNCTION
. Функции могут возвращать значения (таблицы, отдельные строки, примитивные типы данных и т.д.).
CREATE OR REPLACE FUNCTION example_function(param1 INT, param2 TEXT) RETURNS VOID AS $$
BEGIN
INSERT INTO table_name (column1, column2)
VALUES (param1, param2);
END;
$$ LANGUAGE plpgsql;
Вызов:
SELECT example_function(10, 'Sample Text');
МиграцияПри переносе хранимых процедур из MSSQL в PostgreSQL их нужно преобразовывать в функции, переписывая синтаксис и учитывая использование PL/pgSQL.
Управление транзакциями
Что такое транзакция?Транзакция — это единица работы с базой данных, которая выполняется либо полностью (коммит), либо откатывается в исходное состояние (роллбэк), если происходит ошибка. Это обеспечивает целостность данных.
В MSSQL транзакции начинаются с BEGIN TRANSACTION
. Далее выполняются SQL-операции, после которых:
COMMIT TRANSACTION
фиксирует изменения.ROLLBACK TRANSACTION
отменяет все изменения, выполненные с момента начала транзакции.
BEGIN TRANSACTION;
INSERT INTO orders (order_id, customer_id) VALUES (1, 100);
UPDATE customers SET balance = balance - 50 WHERE customer_id = 100;
IF @@ERROR <> 0
BEGIN
ROLLBACK TRANSACTION;
END
ELSE
BEGIN
COMMIT TRANSACTION;
END;
Здесь транзакция проверяет наличие ошибок (@@ERROR) перед фиксацией изменений.
PostgreSQL использует схожий подход, но синтаксис проще:
BEGIN
начинает транзакцию.COMMIT
фиксирует изменения.ROLLBACK
отменяет изменения.
BEGIN;
INSERT INTO orders (order_id, customer_id) VALUES (1, 100);
UPDATE customers SET balance = balance - 50 WHERE customer_id = 100;
IF (SELECT COUNT(*) FROM customers WHERE balance < 0) > 0 THEN
ROLLBACK;
ELSE
COMMIT;
END IF;
Логика проверки ошибок реализуется через SQL или PL/pgSQL конструкции.
Ключевые различия:
- Синтаксис:
- MSSQL требует явного указания
TRANSACTION
, а PostgreSQL использует более короткие команды.
- MSSQL требует явного указания
- Обработка ошибок:
- MSSQL предоставляет встроенную переменную
@@ERROR
для проверки ошибок. - PostgreSQL предлагает более гибкий механизм управления через блоки
EXCEPTION
в PL/pgSQL.
- MSSQL предоставляет встроенную переменную
- Автоматическое управление:
- В PostgreSQL транзакции автоматически обрабатываются в блоках
DO
илиFUNCTION
, что делает код более компактным.
- В PostgreSQL транзакции автоматически обрабатываются в блоках
МиграцияПри переносе логики транзакций с MSSQL на PostgreSQL нужно:
- Переписать проверки ошибок в соответствии с механизмами PostgreSQL.
- Убедиться, что все зависимости между операциями внутри транзакции правильно адаптированы.
- Учесть особенности PostgreSQL, такие как автоматическая фиксация изменений вне явных транзакций.
Заключение
Миграция с MSSQL на PostgreSQL — это не просто перенос данных, а полноценная адаптация системы к новой платформе. Успешная миграция требует учета множества факторов: от различий в типах данных и синтаксисе SQL до особенностей бизнес-логики и работы с транзакциями.
Однако результат стоит затраченных усилий: PostgreSQL предлагает мощные инструменты для масштабирования, гибкость в настройках и поддержку современных стандартов работы с данными. Это делает его привлекательным выбором для компаний, стремящихся к оптимизации затрат и повышению производительности.
Тщательная подготовка, использование подходящих инструментов и детальное тестирование — ключевые шаги к успешной миграции, которая позволит вам использовать все преимущества PostgreSQL в полном объеме.
В этой статье я постарался описать ключевые различия между системами управления базами данных MSSQL и PostgreSQL, которые следует учитывать при миграции. В следующей части мы перейдём к практическим аспектам и обсудим, как можно осуществить миграцию с использованием готовых решений.