Переезд с Windows + MS SQL на Linux + PostgreSQL: 8 типичных ловушек

13.08.26

База данных - Администрирование СУБД

Перенесли базу 1С на 276 ГБ с Windows и MS SQL на Ubuntu и PostgreSQL. Главная неприятность оказалась вообще не про Linux, а вот восемь встреченных по дороге ловушек про него ровно настолько, что каждая стоила отдельного часа. Флаг виртуализации, который врёт; процессы, умирающие вместе с сессией; кластер с английской локалью; автотюнер с work_mem 512 МБ. Ни одной из них нет в чек-листах, которые я читал перед началом.

Мы перенесли базу 1С на 276 ГБ с Windows и MS SQL на Ubuntu и PostgreSQL. Главная неприятность оказалась не там, где её ждут: она вообще не про Linux. А вот восемь ловушек, которые встретились по дороге, про Linux ровно настолько, что каждая стоила отдельного часа. Ни одной из них нет в чек-листах, которые я читал перед началом.

 

Сначала о том, чего НЕ случилось

В прошлой статье я разбирал, почему у нас четыре раза подряд молча вставал перенос на PostgreSQL. Виноваты были невидимые символы: библиотека ICU, через которую сравниваются строки в типах mchar и mvarchar, схлопывает Unicode-совместимые формы. Неразрывный пробел равен обычному, равно No. MS SQL считает такие строки разными, PostgreSQL одинаковыми, уникальный индекс не строится.

Первое, что я сделал на Linux-стенде, это прогнал те же опыты заново. Ожидал разницы: другая операционная система, другая сборка ICU, другая локаль.

SELECT ('a b')::mvarchar = ('a' || chr(160) || 'b')::mvarchar AS nbsp_vs_space;
-- true
SELECT ('No5')::mvarchar = (chr(8470) || '5')::mvarchar        AS numero_vs_No;
-- true
SELECT ('ABC')::mvarchar = ('abc')::mvarchar                   AS case_insensitive;
-- true
SELECT (chr(1077))::mvarchar = (chr(1105))::mvarchar           AS e_vs_yo;
-- false

Ответы совпали с Windows дословно, все четыре.

Вывод, который мне самому не нравился, но он честный: главная проверка перед переездом не имеет отношения к операционной системе. Она про ICU, а ICU одинаков и там, и там. Кто уходит только с MS SQL на PostgreSQL, оставаясь на Windows, получает ровно ту же беду.

Приятная деталь: е и ё ICU различает. У ё нет совместимого разложения, это самостоятельная буква, а не форма. Правило именно про формы NFKD, а не «про похожие символы».

 

Ловушка 1. Флаг виртуализации врёт

Начал со стенда. Посмотрел, можно ли поднять виртуальную машину, и увидел:

VirtualizationFirmwareEnabled : False

Сделал вывод: виртуализация выключена в BIOS, нужен физический доступ к машине и перезагрузка. Написал об этом как о блокере.

Вывод был неверный. Этот флаг показывает ложь ровно тогда, когда гипервизор уже загружен: Windows в таком случае смотрит на прошивку из-под него и честного ответа дать не может. Правильный признак другой:

(Get-CimInstance Win32_ComputerSystem).HypervisorPresent          # правда
(Get-CimInstance Win32_Processor).VirtualizationFirmwareEnabled   # врёт при живом гипервизоре

HypervisorPresent был True с самого начала. Понадобилось только включить роль Hyper-V и перезагрузиться, машина вернулась за минуту.

 

Ловушка 2. Процессы из удалённой сессии умирают вместе с ней

Запустил скачивание установочного образа на стенде через Start-Process внутри Invoke-Command. Скачивание оборвалось на 166,9 МБ ровно в момент закрытия сессии WinRM.

Лечится планировщиком задач: там владелец процесса служба, а не сессия.

$act = New-ScheduledTaskAction -Execute 'curl.exe' -Argument '-L -s -o "файл" "url"'
$pr  = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest
Register-ScheduledTask -TaskName 'download' -Action $act -Principal $pr -Settings $st
Start-ScheduledTask -TaskName 'download'

Тонкость, из-за которой я не сразу понял закономерность: сам перенос ibcmd в похожей ситуации выживал. Разница в том, что он запускался с ключом ожидания внутри живой сессии, а не отсоединённым. Правило простое: если процесс должен пережить закрытие сессии, запускать его надо не из неё.

 

Ловушка 3. Автоустановка Ubuntu всё равно спрашивает согласия

Подготовил автоматическую установку: образ с конфигурацией на томе с меткой cidata, всё по документации. Машина загрузилась, в консоли видно, как отработали все шаги применения конфигурации. И следом:

Confirmation is required to continue.
Add "autoinstall" to your kernel command line to avoid this

Continue with autoinstall? (yes|no)

Конфигурация с тома считается недоверенной: установщик её применяет, но диск без живого «yes» не размечает. Чтобы этого не было, слово autoinstall должно стоять в командной строке ядра, а туда без правки загрузчика в консоли не попасть.

 

Ловушка 4. Клавиатура Hyper-V возвращает успех и ничего не вводит

Консоль виртуальной машины автоматизируется через WMI, и это спасло установку. Экран забирается методом GetVirtualSystemThumbnailImage: он отдаёт сырые пиксели, которые собираются в картинку. Без него я бы гадал, почему процессор простаивает и диск не растёт.

А вот с вводом вышло интереснее:

Метод Итог
Msvm_Keyboard.TypeText('yes') код возврата 0, символы не дошли, приглашение повторилось
TypeKey посимвольно (0x59 0x45 0x53, затем 0x0D) сработало, установка пошла

Нулевой код возврата у TypeText означает «вызов принят», а не «текст введён». Верить надо экрану, а не коду возврата.

 

Ловушка 5. Ubuntu отдаёт логическому тому сотню гигабайт из семисот

Установка прошла, захожу, смотрю диск:

/dev/mapper/ubuntu--vg-ubuntu--lv   98G  7.3G   86G   8% /

Девяносто восемь гигабайт при виртуальном диске в семьсот. Установщик создаёт том на сотню, остальное оставляет свободным в группе томов. Узнали бы мы об этом на середине переноса базы в триста гигабайт.

sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
sudo resize2fs /dev/ubuntu-vg/ubuntu-lv
# стало 686 ГБ

Отсюда пункт в предполётную проверку: смотреть не размер диска, а размер файловой системы под каталогом данных. Это разные числа.

 

Ловушка 6. Кластер молча создаётся с английской локалью

Вот эта, на мой взгляд, самая опасная из восьми, потому что не проявляется сразу.

Пакет PostgreSQL инициализирует кластер сам, при установке. Локаль берёт системную, а на свежей Ubuntu это en_US.UTF-8. Русской базе нужна ru_RU.UTF-8, иначе сортировка строк пойдёт по другим правилам. Обнаруживается это не в день переезда, а через месяц, когда кто-то заметит странный порядок в отчёте.

Пробую задать локаль явно и получаю:

initdb: error: too many command-line arguments (first is "--locale=ru_RU.UTF-8")

Оболочка pg-setup initdb аргументы в initdb не пробрасывает. Локаль берётся из окружения, а sudo окружение вычищает. Рабочий вызов:

sudo locale-gen ru_RU.UTF-8
sudo systemctl stop postgrespro-1c-17
sudo rm -rf /var/lib/pgpro/1c-17/data
sudo env LANG=ru_RU.UTF-8 LC_ALL=ru_RU.UTF-8 LC_COLLATE=ru_RU.UTF-8 LC_CTYPE=ru_RU.UTF-8 \
     /opt/pgpro/1c-17/bin/pg-setup initdb --tune=1c

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

 

Ловушка 7. Расширения, которые не расширения

Мелочь, но время съела. Проверяю, подключены ли online_analyze и plantuner, которые рекомендуют для 1С:

ERROR: расширение "online_analyze" отсутствует
DETAIL: Не удалось открыть управляющий файл расширения ".../online_analyze.control"

При этом параметр plantuner.fix_empty_table в конфигурации живой и работает. Разгадка: они подключаются библиотеками через shared_preload_libraries, а не через CREATE EXTENSION. Искать их в pg_extension бессмысленно, смотреть надо в pg_settings.

 

Ловушка 8. Автотюнер ставит work_mem 512 МБ при 250 соединениях

У сборки PostgreSQL для 1С есть режим автонастройки --tune=1c. Вот что он выставил на машине с 6 ГБ памяти:

Параметр Значение
shared_buffers 1,4 ГБ
work_mem 512 МБ
max_connections 250
effective_cache_size 4,3 ГБ
maintenance_work_mem 370 МБ
max_locks_per_transaction 256

work_mem выделяется на каждую сортировку в каждом сеансе. Двести пятьдесят соединений по 512 МБ это теоретические 128 гигабайт на машине, где их шесть. Автотюнер считает по объёму памяти, но со связкой с max_connections не сверяется.

Это тот случай, когда рекомендация вендора вредна, и сказать об этом надо прямо. В предполётную проверку пошёл отдельный пункт: произведение work_mem на max_connections против физической памяти, с вердиктом «чинить», если оно больше половины.

 

Проверил сервер под 1С и нашёл ноль шрифтов

Когда кластер поехал, я прогнал по серверу проверку, которую сам же и написал в предполётный чек-лист. Ожидал увидеть «нет Arial и Times». Увидел другое:

Сам чек-лист собран в обработку: Проверка базы данных перед миграцией на PostgreSQL. Для переезда с Windows на Linux там отдельный сценарий «СУБД и ОС» - он проверяет ровно то, обо что спотыкаются в этой статье: внешние компоненты без сборки под Linux, шрифты в макетах, тома хранения файлов с незаполненным Linux-путём, Windows-пути в константах и список регламентных заданий для просмотра глазами.

L1_FONTS_TOTAL=0
L1_FONT=Arial;found=0
L1_FONT=Times New Roman;found=0
L1_FONT=Calibri;found=0     ... и так все шесть

Не «нет нужных шрифтов», а нет ни одного. В минимальной установке Ubuntu Server нет даже fontconfig. Печатные формы там не разъедутся, они просто не отрисуются.

Заодно та же проверка показала, что системная локаль осталась английской:

L1_LOCALE=LANG=en_US.UTF-8;LC_COLLATE="en_US.UTF-8";...

А кластер PostgreSQL я поднял с ru_RU.UTF-8. Это два разных места, и починка одного не чинит другое. Хорошая иллюстрация к тому, почему проверок должно быть много и почему они должны быть отдельными.

Учётная запись и лимиты, кстати, тоже оказались в состоянии «как поставилось»: ulimit -n равен 1024 при рекомендованных для 1С 65536, vm.swappiness шестьдесят при рекомендованных единицах, huge pages в режиме madvise вместо never. Ничего из этого не мешает поставить сервер, и всё это вылезет под нагрузкой, когда люди уже работают.

 

Про память, и почему цифра в конфиге ничего не значит

Отдельная история, которая стоила двух сорванных прогонов и хорошо иллюстрирует, чем стенд отличается от продуктива.

Перенос дважды упал с ошибкой:

Ошибка СУБД: Microsoft OLE DB Driver for SQL Server:
Недостаточно свободной памяти в буферном пуле. native=802

Первая мысль: у SQL Server мало памяти, подниму лимит. Поднял с 3 до 6 ГБ. Упало снова. Полез смотреть, что происходит на самом деле:

SELECT
  (SELECT CAST(value_in_use AS int) FROM sys.configurations
    WHERE name = 'max server memory (MB)')                       AS max_mem_setting,
  (SELECT CAST(cntr_value/1024 AS int) FROM sys.dm_os_performance_counters
    WHERE counter_name = 'Target Server Memory (KB)')             AS target_mb,
  (SELECT process_physical_memory_low FROM sys.dm_os_process_memory) AS low_flag;
max_mem_setting  target_mb  low_flag
6144             290        1

Настройка разрешает шесть гигабайт, а SQL Server сам держит цель на 290 мегабайтах и не снимает флаг нехватки памяти. Потому что брать их неоткуда: на хосте виртуальная машина, рабочий стол и суммарно 10,8 ГБ рабочих наборов при 15,8 физических.

Поднятие настройки было пустым действием. Цифра в конфиге это разрешение, а не память в наличии, и SQL Server честно от неё отказывается, когда операционная система сигналит о дефиците. Помогло другое: ужать виртуальную машину, снизить shared_buffers на приёмнике и уменьшить порцию переноса с 10 000 строк до 1000. Ошибка 802 возникает на конкретном запросе памяти, и уменьшение порции бьёт по причине, а не по симптому.

 

Итог переноса на Linux

Показатель Значение
Время переноса 3 часа 30 минут (209,9 мин, код возврата 0)
Размер на Linux 300,19 ГБ
Таблиц 4470
Индексов 10 623, из них уникальных 9111
Невалидных индексов 0

Те же цифры я снял днём раньше с переноса на Windows-PostgreSQL. Они совпали до единицы: 4470 таблиц, 10 623 индекса, 9111 уникальных, 300 ГБ. Две разные операционные системы дали структурно идентичный результат, и это, пожалуй, лучший аргумент в пользу того, что выбор ОС для самого переезда вторичен.

По времени сравнение некорректное, и я это скажу прямо, чтобы не вводить в заблуждение: Windows-прогон занял 2 часа 28 минут, Linux - 3 часа 30. Но условия были разные. После двух падений по памяти я снизил параллельность до одного потока и уменьшил порцию с 10 000 строк до 1000, а целевая машина получила 2,5 ГБ памяти вместо шести. Медленнее оказался не Linux, а моя осторожность.

 

А вот это я не ожидал: таблицы растут неравномерно

База в целом выросла на 8,9 процента. Но когда я сравнил таблицы поимённо, средняя цифра рассыпалась:

Таблица MS SQL PostgreSQL Отношение
_AccRgED14402X1 11,17 ГБ 39,92 ГБ ×3,6
_AccRg14374X1 13,84 ГБ 30,91 ГБ ×2,2
_Document229X1 9,20 ГБ 14,74 ГБ ×1,6
_InfoRg7855X1 47,38 ГБ 44,47 ГБ ×0,94

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

Почему так, я до конца не проверял, и врать не буду. Правдоподобное объяснение: у PostgreSQL заголовок строки 24 байта против 7 у MS SQL, и на узких таблицах регистров бухгалтерии, где строк десятки миллионов, а полезных данных в строке мало, эта разница множится. Плюс индексы там занимают больше самих данных. Проверяемая гипотеза, но проверять её надо отдельно.

Практический вывод от этого не зависит: смотрите на свои топ-таблицы, а не на общий размер базы. Список даёт любой скрипт вроде того, что я приводил в прошлой статье.

 

Что я об этом думаю

Если свести восемь ловушек к одному, получится так: почти каждая была не отказом, а молчанием. Флаг виртуализации не соврал грубо, он ответил на другой вопрос. Скачивание не выдало ошибку, оно просто остановилось. Клавиатура вернула успех и ничего не сделала. Кластер не пожаловался на локаль, он взял ту, что нашёл. Автотюнер не предупредил про соединения, он посчитал по памяти.

Поэтому единственный работающий приём, который я вынес из этого переезда, звучит скучно: после каждого шага проверять результат независимым способом. Не «команда отработала без ошибки», а «диск действительно того размера», «локаль действительно русская», «текст действительно введён». На стенде это стоит минут. В окне переключения, когда база лежит, а люди ждут, это стоит совсем других денег.

И повторю главное из первой статьи, потому что оно от операционной системы не зависит: прогоните проверку на невидимые символы. Шесть минут на копии, и вы избавились от риска, который срывает перенос молча и на любой платформе.

Проверка, о которой речь, собрана в обработку: Проверка базы данных перед миграцией на PostgreSQL. Сценарий «СУБД и ОС» закрывает ровно то, о чём эта статья: внешние компоненты без сборки под Linux, шрифты макетов, тома хранения с незаполненным Linux-путём, Windows-пути в константах.

Другие наши инструменты диагностики 1С:

Вступайте в нашу телеграмм-группу Инфостарт

Linux Ubuntu PostgreSQL Postgres Pro переезд 1С на Linux миграция с Windows сервер 1С на Linux локаль кластера work_mem huge pages шрифты Linux Hyper-V LVM импортозамещение ibcmd перенос базы 1С администрирование 1С initdb systemd

Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

См. также

Администрирование СУБД Системный администратор Программист Бесплатно (free)

5,5 тысячи пользователей в единой базе 1С, розница в режиме 24/7 и SLA 99,98% – в таких условиях любая авария быстро превращается в очереди на кассах, потерю денег и давление со стороны бизнеса. Показываем, как выстроить процесс аварийно-восстановительных работ: от первых алертов и базового скрининга системы до подключения команды, проверки гипотез и дебрифа после инцидента. Разбираем, как метрики, дашборды, техжурнал, Zabbix, Prometheus, Grafana, Telegram-боты и скрипты помогают не гадать, а быстро находить причину проблемы. На реальных авариях объясняем, почему «быстро» не должно означать «рискованно», как работа над ошибками снижает панику и почему каждая авария может сделать систему надежнее.

11.08.2026    1538    jul.dolganova    8    

21

Облачные сервисы, хостинг Сервера Нейросети Программист Бесплатно (free)

В последние годы спор «облако или локалка» стал одним из самых горячих в мире работы с нейросетями. Давайте разберемся.

03.08.2026    2823    dsdred    48    

11

Администрирование СУБД 1С 8.3 1С:ERP Управление предприятием 2 Бесплатно (free)

База 1С:ERP размером 646 Гб, полное маскирование за 5 часов - без создания промежуточной незащищенной копии. Разбираем бесплатный pg_anon на сквозном примере с реального продуктива.

27.07.2026    2382    Tantor    16    

13

HighLoad оптимизация Администрирование СУБД Программист Россия Бесплатно (free)

Если вы работаете с 1С на PostgreSQL и жалуетесь на тормоза — скорее всего, дело в join predicate pushdown, которого в стандартном PostgreSQL нет. В MS SQL Server этот механизм работает «из коробки», и при миграции именно запросы к виртуальным таблицам 1С бьют по производительности сильнее всего. В этой статье — реальный кейс от Postgres Professional с разбором плана выполнения, ручным экспериментом и доработкой планировщика СУБД, которая ускорила запросы от 22 до 54 000 раз.

16.06.2026    8647    postgres_professional    13    

12

HighLoad оптимизация Администрирование СУБД Системный администратор Программист 1С:Предприятие 8 Бесплатно (free)

Вышел релиз СУБД Tantor Postgres 18, и мы хотим рассказать о его новых возможностях для работы с приложениями на платформе "1С:Предприятие". В обзоре разберем улучшения планировщика, по традиции коснемся работы временных таблиц и не обойдем вниманием вспомогательные утилиты, которые упрощают поиск и диагностику проблем в высоконагруженных системах. За каждым пунктом - реальные запросы 1С, реальные рабочие базы и сотни часов тестирования!

16.06.2026    3310    Tantor    7    

10

Администрирование СУБД Системный администратор Программист 1С:Предприятие 8 Россия Бесплатно (free)

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

01.06.2026    8002    2ncom    30    

11

Сервера Системный администратор Программист 1С:Предприятие 8 Бесплатно (free)

Пошаговый опыт миграции файловой базы 1С УНФ 1.6 с арендованного сервера на собственную железку в частный дом. Разбираем: сборку ПК за 50 тыс. руб., нюансы публикации базы через IIS на Windows 11, решение проблем с правами доступа и настройку проброса портов на роутере TP-Link, а так же настройка ежедневного бекапа c архивацией в облако встроенными средствами Windows. Итог — быстрая работа через веб-клиент без арендных платежей и кошмаров о потере данных

12.05.2026    2575    war41k    34    

11

Администрирование СУБД Системный администратор Программист Бесплатно (free)

Статья рассказывает об опыте перевода больших баз с MSSQL на Postgres и годовой эксплуатации после перехода. Показано, с какими ограничениями утилиты ibcmd можно столкнуться при миграции больших баз и какие подходы помогают безопасно обходить эти проблемы. Приведены наиболее интересные кейсы, выявленные в эксплуатации: особенности настроек Postgres, поведение оптимизатора, тонкости работы логики и статистики, а также редкие, но критичные ситуации с производительностью. Материал будет полезен тем, кто планирует переход на Postgres и хочет заранее понимать реальные риски, подводные камни и проверенные практики их преодоления.

20.04.2026    8975    berserg    12    

27
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Cocky_Idiot 38 18.08.26 01:03 Сейчас в теме
Ловушка 6. Кластер молча создаётся с английской локалью

странное... в сборке от 1С(и в ванильном) локаль можно(нужно!) явно указать ключом initdb:
sudo -u postgres /usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data --allow-group-access --locale=ru_RU.UTF-8 --data-checksums

и да, локаль, ессно должна быть предварительно создана через locale-gen.

проверено, мин нет.

P.S. Для самой службы 1С локаль задается через systemd
[idiot@1c ~]$ cat /etc/systemd/system/srv1cv8-8.3.27.1936@default.service
[Unit]
Description=1C:Enterprise Server 8.3 (8.3.27.1936) (%I)
Requires=network.target

[Service]
Environment=LANG=ru_RU.UTF-8
....
Показать
2. nedomolkov.ivan 113 18.08.26 12:27 Сейчас в теме
(1)
и да, локаль, ессно должна быть предварительно создана через locale-gen.


Спасибо, полезное уточнение, только мы про разные вызовы.

Прямой initdb ключи принимает, тут вы правы. У меня в статье вызов идёт через обёртку
pg-setup от Postgres Pro, и вот она аргументы в initdb не пробрасывает, отсюда и
too many command-line arguments. Поэтому и пришлось лезть через env.

Если звать initdb напрямую, теряется --tune=1c, а это готовый набор параметров под 1С,
ради него обёртку и держат. Получается так: обычный PostgreSQL и сборка от 1С - ваш ключ,
Postgres Pro для 1С - env перед pg-setup.

Про LANG в юните службы 1С в статью не попало, а зря. Дельное дополнение, спасибо.
Для отправки сообщения требуется регистрация/авторизация