Yandex Metrika
sanches.free

Типовые ошибки при миграции MySQL → PostgreSQL с pgloader и как их снять

Введение

При переносе на PostgreSQL сообщения об ошибках часто выглядят страшнее, чем есть на самом деле. Ниже — несколько повторяющихся классов проблем, с которыми сталкиваются команды, использующие pgloader; для проекта на 1С‑Битрикс прямой параллели с ядром нет, но те же паттерны встречаются в смежных PHP-сервисах и интеграционных базах рядом с порталом.

Клиент pgloader не подключается к MySQL

Типичный текст содержит MYSQL-UNSUPPORTED-AUTHENTICATION: драйверы стека Common Lisp не понимают дефолтный для MySQL 8 механизм caching_sha2_password. Практичный обход для служебного учёта миграции — временно перейти на mysql_native_password и ограничить хост, с которого разрешено подключаться.

ALTER USER 'replica_loader'@'%'
  IDENTIFIED WITH mysql_native_password BY 'REPLACE_WITH_SECURE_VALUE';
FLUSH PRIVILEGES;

После переноса верните политику паролей и сетевые ACL в соответствие с регламентом.

Виртуальный столбец в источнике и «его нет» в целевой схеме

В MySQL могли добавить GENERATED … VIRTUAL столбец вручную, а Laravel/Doctrine-миграции на стороне Postgres его не создают. Тогда поток pgloader упирается в попытку писать в колонку, которой физически нет в Postgres. Если виртуальное поле воспроизводимо формулой, лучше оформить его как VIEW или вычисляемое выражение уже в Postgres; если нет — удалите столбец на источнике перед финальным забегом или смоделируйте его там, где это допустимо по данным.

ALTER TABLE web_sessions DROP COLUMN utm_utm_src;

Имена таблиц/полей заменены; подставьте свои из сообщения об ошибке.

Символ U+0000 в JSON-тексте

PostgreSQL не принимает нулевой байт внутри текстовых/JSON-путей, поэтому 22P05: unsupported Unicode escape sequence при COPY часто означает, что в колонке лежит «грязный» JSON или сериализация объектов PHP с управляющими символами. Путь исправления двойной: убрать источник (корректная сериализация без приватных полей-magic) и санировать уже записанные строки до повторной загрузки.

Пустая строка вместо UUID

Сообщение вида invalid input syntax for type uuid: "" говорит, что приложение сохранило пустую строку в столбце, который в Postgres строже. До загрузки нормализуйте значения в NULL или удалите заведомо битые строки — шаблон тот же, меняются только таблицы.

UPDATE web_sessions SET source_id = NULL WHERE source_id = '';
DELETE FROM search_requests WHERE profile_uuid = '';
UPDATE filters_ui SET connector_id = NULL WHERE connector_id = '';

Админки Horizon/Telescope и PEM

Если в логах фигурируют PEM routines: no start line, приложение может пытаться читать повреждённый ключ JWT из таблицы вроде jwt_public_keys. На тестовом контуре иногда быстрее очистить таблицу и заново выпустить ключи уже в среде Postgres, чем восстанавливать битые записи вслепую.

artisan migrate после оборванной загрузки

Если в BEFORE LOAD DO временно переименовали public, а прогрузка оборвалась, Laravel может жаловаться, что некуда создавать таблицу migrations. Проверьте реальное имя схемы в \dn и верните public.

ALTER SCHEMA "staging_core_tmp" RENAME TO "public";

Итог

Большинство ошибок сводится к несогласованности типов между СУБД, «устаревшим» клиентом MySQL и хвостами ручных правок DDL. Перед боевым окном делайте сухой прогон, фиксируйте DDL-дифф и автоматизируйте санитизацию данных, чтобы второй запуск pgloader был предсказуемым.

Не хотите копаться сами?

Починю за 1-3 дня. Без предоплаты — оплата по результату.

15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии