Ситуация, когда сервер управления базами данных (СУБД) завершает работу аварийно при выполнении обычного запроса, является критической для любой информационной системы. В случае с PostgreSQL и 1С это часто проявляется в виде сообщения "процесс сервера был завершён по сигналу 11: Ошибка сегментирования" (Segmentation fault). Это означает, что процесс postgres попытался обратиться к участку оперативной памяти, который ему не принадлежит или недоступен, что приводит к немедленному закрытию всех активных соединений и переходу СУБД в режим восстановления.
Рассмотрим подробно причины возникновения этой ошибки, проанализируем структуру проблемного запроса и выработаем пошаговый план решения проблемы.
Проанализируем запрос, который приводит к падению. В терминах языка запросов 1С он выглядит следующим образом:
ВЫБРАТЬ
РезультатыОбменаДанными.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
ВЫБОР
КОГДА РезультатыОбменаДанными.ТипПроблемы В (ЗНАЧЕНИЕ(Перечисление.ТипыПроблемОбменаДанными.ОшибкаВыполненияКодаОбработчиковПриПолученииДанных))
ТОГДА НЕОПРЕДЕЛЕНО
ИНАЧЕ 3
КОНЕЦ КАК ДействиеПриОбмене,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ РезультатыОбменаДанными.ПроблемныйОбъект) КАК Количество
ИЗ
РегистрСведений.РезультатыОбменаДанными КАК РезультатыОбменаДанными
СГРУППИРОВАТЬ ПО
РезультатыОбменаДанными.УзелИнформационнойБазы,
ВЫБОР
КОГДА РезультатыОбменаДанными.ТипПроблемы В (ЗНАЧЕНИЕ(Перечисление.ТипыПроблемОбменаДанными.ОшибкаВыполненияКодаОбработчиковПриПолученииДанных))
ТОГДА НЕОПРЕДЕЛЕНО
ИНАЧЕ 3
КОНЕЦ
При трансляции этого запроса в SQL для PostgreSQL (как видно из технологического журнала или логов СУБД), платформа 1С генерирует сложную конструкцию с использованием CASE WHEN, CAST(0 AS NUMERIC) и конкатенации полей bytea (двоичные данные). Особое внимание стоит уделить блоку агрегации:
(COUNT(DISTINCT CASE WHEN T1._FLD78286_TYPE = '\\001'::BYTEA THEN '\\001'::BYTEA END)
+ COUNT(DISTINCT CASE WHEN T1._FLD78286_TYPE = '\\010'::BYTEA THEN T1._FLD78286_RTREF || T1._FLD78286_RRREF END))
Здесь происходит подсчет уникальных ссылок, которые в базе данных представлены составными типами. Сочетание COUNT(DISTINCT ...) с условиями и конкатенацией полей _RTREF и _RRREF создает серьезную нагрузку на механизмы управления памятью в PostgreSQL. Для сопоставления полей и таблиц СУБД с объектами метаданных 1С можно использовать обработку для анализа структуры хранения базы данных.
Когда СУБД падает, в логе регистрируется событие следующего вида:
СООБЩЕНИЕ: процесс сервера (PID 507045) был завершён по сигналу 11: Ошибка сегментирования
После этого сервер автоматически перезапускается и входит в режим восстановления (Recovery mode), проигрывая записи из WAL (Write Ahead Log), чтобы обеспечить целостность данных. Если перезагрузка сервера не помогает и запрос стабильно "вешает" систему, значит, мы имеем дело либо с багом в коде СУБД, либо с физическим повреждением страниц данных.
Начиная с версии PostgreSQL 11, по умолчанию включена функция JIT (Just-In-Time compilation). Она призвана ускорять выполнение сложных запросов, компилируя их части в машинный код "на лету". Однако на практике сложные запросы 1С с множеством CASE и вложенных функций часто вызывают ошибки в оптимизаторе JIT, что ведет к падению процесса с Signal 11.
Рассмотрим, как проверить эту теорию. Попробуем отключить JIT для текущей сессии или глобально в файле postgresql.conf:
-- Отключение JIT в рамках одной сессии для теста
SET jit = off;
-- После этого выполните проблемный запрос
Если после отключения JIT запрос выполняется успешно, значит, причина найдена. В этом случае рекомендуется оставить jit = off в настройках сервера навсегда, так как для типичных нагрузок 1С JIT редко дает существенный прирост производительности, но часто снижает стабильность.
Еще одной частой причиной Segmentation fault является некорректная работа параллельных рабочих процессов (Workers) при обработке сжатых таблиц или сложных соединений. Если вы используете редакцию Postgres Pro с включенным расширением CFS (Compressed File System), как в нашем примере (CFS version 0.54), риск возрастает.
Проанализируем влияние параллелизма, отключив его:
SET max_parallel_workers_per_gather = 0;
Это заставит планировщик выполнять запрос в один поток. Если падения прекратились, это указывает на баг в механизме обмена данными между параллельными процессами при агрегации COUNT(DISTINCT).
Для выполнения группировок PostgreSQL может использовать два метода: HashAggregate (строит хеш-таблицу в памяти) и GroupAggregate (сортирует данные и группирует их последовательно). При использовании очень длинных ключей группировки (а в запросе 1С ключи CASE...END дублируются в SELECT и GROUP BY), хеш-таблица может вызвать переполнение выделенного буфера.
Попробуем заставить сервер использовать более стабильный, хоть и медленный, алгоритм сортировки:
SET enable_hashagg = off;
Если настройки планировщика не помогают, выясним, не вызвано ли падение повреждением данных. Ошибка сегментации может возникнуть, когда процесс пытается прочитать "битую" ссылку в TOAST-таблице (область для хранения больших значений полей, таких как bytea). Для формирования команд обслуживания индексов СУБД можно использовать генератор скрипта для индексации таблиц PostgreSQL.
Выполним обслуживание проблемной таблицы:
REINDEX TABLE _InfoRg78282;VACUUM FULL _InfoRg78282;Важное замечание: если во время выполнения VACUUM FULL сервер снова упадет с ошибкой Signal 11, это стопроцентное подтверждение физического повреждения данных на диске.
Разберем, как можно изменить сам запрос, чтобы снизить вероятность падения СУБД. В исходном запросе используется конструкция, где в одну колонку (ДействиеПриОбмене) могут попадать разные типы: Неопределено (которое 1С превращает в сложную структуру в SQL) и число 3.
Рекомендации по оптимизации:
Неопределено и чисел в одну колонку без крайней необходимости.Неопределено на конкретное числовое значение (например, 0 или -1), которое будет обрабатываться логикой приложения. Это упростит SQL-код и избавит планировщик от лишних приведений типов (CAST).ПроблемныйОбъект. Если это составной тип, включающий множество справочников и документов, COUNT(DISTINCT) по нему будет крайне тяжелым.Мы проанализировали ситуацию с падением PostgreSQL при работе с 1С. Основными шагами к исправлению являются:
SELECT помогает избежать генерации избыточно сложного SQL.Соблюдение этих правил позволит обеспечить бесперебойную работу сервера и исключить внезапные перезагрузки СУБД из-за ошибок сегментирования.