1С и PostgreSQL: пять граблей, на которые наступают при переезде

Клиент решил уйти с Microsoft SQL Server на PostgreSQL. Причина стандартная — лицензии. SQL Server Standard стоит денег, PostgreSQL бесплатный. Экономия понятна. Подводные камни — нет.

Переезд прошёл за день. Выгрузка-загрузка через dt-файл, всё штатно. А потом начались звонки. Первый — через два дня. Последний — через три месяца. Пять проблем, которые мы собрали на одном проекте. Все — типичные.

Грабли первые: VACUUM не настроен

PostgreSQL не удаляет старые версии строк при UPDATE и DELETE. Он помечает их как мёртвые и оставляет в таблице. VACUUM — процесс, который чистит эти мёртвые строки. Без него таблицы распухают, индексы деградируют, запросы замедляются.

Autovacuum включён по умолчанию. Но его настройки рассчитаны на средние нагрузки. В 1С нагрузка специфическая: регистры накопления и бухгалтерии обновляются массово при проведении документов. Тысячи строк за одну транзакцию. Autovacuum не успевает.

Через месяц таблица регистра бухгалтерии выросла с 2 ГБ до 8 ГБ. Живых строк — на 2 ГБ. Остальное — мертвый груз. Запрос оборотно-сальдовой ведомости, который раньше выполнялся за 3 секунды, стал выполняться за 25.

Решение: настроить autovacuum агрессивнее для таблиц 1С. autovacuum_vacuum_scale_factor = 0.01 (вместо дефолтных 0.2). autovacuum_analyze_scale_factor = 0.005. Для самых нагруженных таблиц — ещё агрессивнее, через ALTER TABLE SET. И запланировать полный VACUUM ANALYZE раз в неделю в нерабочее время.

Рост таблицы без VACUUM: живые vs мёртвые строки

Грабли вторые: планы запросов и отсутствие хинтов

В SQL Server есть подсказки оптимизатору — query hints. OPTION (HASH JOIN), OPTION (RECOMPILE), FORCESEEK. 1С не использует их напрямую, но SQL Server хорошо понимает типичные паттерны запросов 1С и строит эффективные планы.

PostgreSQL использует другой оптимизатор. Он принимает другие решения. Запрос, который на SQL Server выполнялся с Index Seek за полсекунды, на PostgreSQL может выполняться с Seq Scan за 30 секунд. Не потому что PostgreSQL хуже — потому что статистика другая, стоимостные модели другие, и оптимизатор выбирает другой план.

Самая частая проблема — Nested Loop вместо Hash Join на больших выборках. PostgreSQL недооценивает количество строк, выбирает Nested Loop, и запрос улетает в космос.

Решение: регулярный ANALYZE (обновление статистики). Настройка random_page_cost (снизить с 4 до 1.1-1.5 для SSD-дисков — по умолчанию PostgreSQL считает, что random read в 4 раза дороже sequential, что верно для HDD, но не для SSD). И effective_cache_size — выставить в 75% оперативной памяти сервера.

Грабли третьи: блокировки и row-level locking

В SQL Server 1С использует управляемые блокировки через менеджер блокировок платформы. Это работает предсказуемо — разработчик контролирует гранулярность.

В PostgreSQL блокировки работают иначе. MVCC (Multi-Version Concurrency Control) даёт каждой транзакции свой снимок данных. Читатели не блокируют писателей. Звучит идеально. На практике — появляются дедлоки в местах, где на SQL Server их не было.

Типичный сценарий: два пользователя одновременно проводят документы, которые двигают один и тот же регистр накопления. На SQL Server менеджер блокировок 1С разрулит — поставит одного в очередь. На PostgreSQL транзакции стартуют параллельно, обе пытаются обновить одни и те же строки, одна получает deadlock detected.

Решение: проверить, что в конфигурации включён режим управляемых блокировок (а не автоматических). Если конфигурация старая и работает в автоматическом режиме — это первое, что нужно исправить перед переездом. Второе — настроить deadlock_timeout (по умолчанию 1 секунда, для 1С лучше 3-5 секунд, чтобы дать транзакциям время разрешиться самостоятельно).

Сравнение блокировок MS SQL vs PostgreSQL для 1С

Грабли четвёртые: кодировка и сортировка

При создании базы PostgreSQL нужно указать кодировку и локаль. Для 1С — только UTF-8 и локаль ru_RU.UTF-8 (или en_US.UTF-8). Если создать базу с неправильной локалью — русские символы будут сортироваться неправильно.

Звучит мелко. На практике: отчёт по контрагентам, отсортированный по алфавиту, показывает «Я» перед «А». Бухгалтер в шоке, звонит: «У вас программа сломалась».

Ещё хуже — локаль влияет на работу индексов. Если индекс создан с одной локалью, а запрос использует другую — индекс не используется. Seq Scan по таблице с миллионом строк.

Решение: при создании кластера PostgreSQL задать правильную локаль сразу. Проверить: SELECT datcollate, datctype FROM pg_database WHERE datname = current_database(). Если не ru_RU.UTF-8 — пересоздать кластер. Да, именно пересоздать. Изменить локаль существующего кластера нельзя.

Грабли пятые: бэкапы через pg_dump — не бэкапы

pg_dump создаёт логический дамп базы. Для маленьких баз — нормально. Для базы 1С на 50 ГБ — pg_dump работает два часа и создаёт файл, из которого восстановление займёт четыре часа. Шесть часов простоя при аварии.

Альтернатива — pg_basebackup. Физический бэкап всего кластера. Работает быстрее, восстановление — минуты (просто скопировать файлы и запустить). Плюс — поддержка PITR (Point-In-Time Recovery): можно восстановить базу на любой момент времени, а не только на момент бэкапа.

Для production-серверов 1С на PostgreSQL — только pg_basebackup с WAL-архивированием. Настройка: archive_mode = on, archive_command = копирование WAL-файлов в отдельное хранилище. Бэкап раз в сутки, WAL-файлы копируются непрерывно. Максимальная потеря данных — последние несколько секунд.

pg_dump оставить для переноса данных между серверами и для создания копий для тестирования. Не для бэкапов production.

Сравнение стратегий бэкапа PostgreSQL для 1С

Стоит ли переезжать

Да, если готовы потратить время на настройку. PostgreSQL для 1С работает. На некоторых нагрузках — даже быстрее SQL Server. Но из коробки — нет. Нужна настройка под конкретную базу, конкретную нагрузку, конкретное железо.

Экономия на лицензиях SQL Server — сотни тысяч рублей в год. Настройка PostgreSQL — два-три дня работы специалиста. Математика простая. Но эти два-три дня нужны. Без них получите базу, которая работает медленнее, чем на SQL Server, и клиент скажет: «Верните как было».

Мы переводили на PostgreSQL около десяти баз за последние два года. Ни одна не вернулась обратно. Но каждая потребовала настройки. Волшебной кнопки «переехать и забыть» не существует.