Закончилось основное событие года в мире PostgreSQL - PgConf 2025. В статье рассматривается патч, который ускоряет закрытие месяца в 1С-ERP в 10 раз, что довольно значительно. Обзор патча был представлен в докладе "Быстрое закрытие месяца в 1С:ERP на PostgreSQL" или "Закрывай месяц в 1С ERP на PostgreSQL быстро и незаметно".
С 1С:ERP я не знаком, но знаю, что для 1С выпускаются специальные сборки PostgreSQL. Наполнившись решимостью узнать, что в этом 1С происходит я пожертвовал докладом про карту видимости (который проходил в соседнем зале) и не пожалел.
Я узнал, что в 1С никто ничего не делает, кроме как месяца закрывают и больше никого ничего не интересует, а также то, что по статистике пользователи приложения 1С:ERP делают что-либо, в среднем, раз в 20 минут. "Закрытие месяца" - набор расчетов и действий, которые могут выполняться часами. При этом с первого раза месяц обычно не закрывается, так как обнаруживаются ошибки учёта, которые должны быть исправлены и закрытие месяца повторяется заново. И так несколько раз. В докладе осветили нюансы установки границы итогов, удобство использования клонов кластера баз данных, описали причины проблем: вкратце, как я понял, проигрываются проводки, удаляется добавляется много строк.
Основная интрига доклада была в том, что "секретный патч Фёдора Сигаева" ускоряет закрытие месяца в 10 раз (на порядок!). На этом месте я проснулся и встрепенулся. Не каждый день встретишь ускорение на порядок. Про патч докладчик сказал "что-то там патч поправляет в статистике. Этот патч ещё никуда не вышел. Не могу сказать, когда он появится, а может и не появится". После этого мне резко этот патч понадобился, хотя у меня нет 1С. Я обернулся в поисках моральной поддержки и спросил слушавшего доклад чуть позади меня: "что за патч, это fasttrun что ли?". Участник сказал "Не знаю. Спроси Сигаева" и указал направление позади себя.
Смысл патча в том, что вместо Nested Loop для многих запросов начинает выбираться Hash Join. C Nested Loop планировщик часто ошибается, недооценивая число строк в выборке. При сколько-нибудь большом числе строк, метод соединения Nested Loop становится чрезвычайно медленным и ошибка планировщика фатальна. При этом планировщик, как ни собирай статистику, неизменно использует Nested Loop в запросах, генерируемых 1С из-за особенностей конструирования запросов. Установить параметр конфигурации enable_nestloop = off нельзя, так как Nested Loop эффективен (не имеет задержки на отдачу первой строки) и для большого числа запросов с небольшим числом соединяемых строк оптимален. Отказ от этого способа соединения приведет к замедлению выполнения таких запросов.
Выслушав доклад, заинтересованные участники конференции окружили Фёдора Сигаева с политкорректным вопросом "Когда в PGpro Enterprise появится патч?" думая, что патч высокой секретности, если и появится, то только в Enterprise версии. Фёдор сказал кратко: "патч выложен в коммитфесте". Что характерно, заинтересованных участников было немного - человек 5 при достаточно заполненном зале. Большая часть людей не решались задать нескромный вопрос. После ответа Федора я не то чтобы присвистнул, но воодушевился. Ответ означал, что патч несекретный, а самый что ни на есть открытый - безвозмездно передан сообществу. В наше суровое время такое редко встретишь. Более того, похоже есть шанс добавления (в будущем) в ванильную версию. На конференции был свидетелем монолога "Ой Рогов, тот самый что ли?". На что второй мэтр добродушно ответил: "тот самый", а не "глаза разуй".

Воодушевленный существованием, а главное, доступностью патча, я побрёл к сцене ловить докладчика, который, как мне показалось, разбирался в этих самых 1С. Меня издавна глодал вопрос: сколько временных таблиц может создать 1С в одной сессии. Докладчик в докладе сказал, что в час 1С средней руки создаёт миллион временных таблиц, а в месяц миллиард.
Я подошел к группе товарищей, окруживших харизматичного докладчика и смиренно стал слушать о чем говорят умные люди, ожидая удобного момента ввернуть свой вопрос. В это время невдалеке Фёдор объяснял Ивану Панченко в терминах линейных и квадратичных оценок что делает патч. Не только я был заинтригован патчем.
Самостоятельно искать патч я не стал, так как не силён в коммитфестах. В общем, кое-как нашел патч (ну как нашел, помогла техподдержка): https://www.postgresql.org/message-id/flat/9789f79b-34f0-49ee-9852-783392a3615c@sigaev.ru В обсуждении Илья Евдокимов из Тантор Лабс поддержал Фёдора Сигаева, ответив на разогревающий вопрос Тома Лейна:

Вспомнив доклад "PostgreSQL: истории, оставленные между строк кода" несравненной Екатерины Соколовой, который был несколькими часами раньше, я углубился в чтение комментариев между строк кода.
Скрытый текст
В этом году Роман Фролов задал Екатерине два вопроса и не онлайн, а оффлайн, специально приехав на конференцию. Но сердце красавицы непреклонно - приз за лучший вопрос она отдала Евгению Моргунову. Призом, похоже, оказалась книга, написанная самим же Евгением и получился первоапрельский подарок. Евгений был польщён
Технические детали патча
В этом разделе душный обзор патча, который можно пропустить.
В комментарии кода, который исправляет патч, неизвестный разработчик, написавший этот древний код, вопрошал доколе?:
* Essentially, we are assuming that the not-yet-known
* comparison value is equally likely to be any of the possible
* values, regardless of their frequency in the table. Is that a good
* idea?
"Is that a good idea?" Идея, конечно, была плохой. И этот текст комментария был заменён патчем на объяснение сути этого самого патча:
Estimate the selectivity as quadratic mean of non-null fraction
divided by number of distinct values and set of MCV selectivities.
Use quadratic mean because it includes the squared deviation (error)
as well and here it would be nice to compute upper limit of estimation
to prevent wrong choose of nested loop, for example.
Пример структуры проблемных запросов:
explain analyze
SELECT
COUNT(*)
FROM
t1
LEFT JOIN
t2
ON t2.b = t1.a
AND t2.c = 0 //line of interest
;
С закомментированной строкой 'line of interest' все работает отлично, без проблем, но с этой строкой мы получим другой план, гораздо худший. Интересно, что столбец t2.c содержит только одно значение (ноль). Планировщик выбирает вложенный цикл, вместо хэш-соединения и делает неправильную оценку:
Index Only Scan using i1_t2 on t2 (.. rows=6 ..) (.. rows=3555 loops=2000)
Index Cond: ((c = 0) AND (b = t1.a))
Предполагалось шесть строк, но при выполнении получено 3555 строк. Это произошло потому, что функция var_eq_non_const() предполагает равномерное распределение столбца t2.b, что неверно.
Сам патч, который должен сделать закрытие месяца в 1C быстрее на порядок состоит из нескольких строк:
int i;
double sum_selec = 0.0;
+
/*
* Compute quadratic mean, walk on array in reverse direction to
* do not lose accuracy. We don't bother about sslot.nnumbers
* equality to zero, because in this case we just get the same
* result. But equality to zero is unlikely.
*/
for(i=sslot.nnumbers - 1; i>=0; i--)
sum_selec += sslot.numbers[i] * sslot.numbers[i];
selec = sqrt((selec * selec + sum_selec) / ((double)sslot.nnumbers + 1.0));
Глядя на эти строки мне даже захотелось написать какой-нибудь патч. Но, надо знать какую формулу и в какую часть кода вставить. В поисках жертвенной функции могут помочь комментарии с вопросительными предложениями типа "правильно ли это?".
Когда патч появится в официальных форках? В первую очередь патч появится в Tantor SE 1C 17 версии, так как Илья Евдокимов из Тантор первым осознал ценность патча. Будет ли подправлена формула в патче (чтобы исключить деградацию на части запросов, где Seq Scan меняется на Index Scan) это науке неизвестно.
В ванильной версии PostgreSQL патч появится не раньше 18 версии. Те, кто самостоятельно компилируют версии PostgreSQL, могут его использовать. В комментариях подсказали ссылку на статус патча в сообществе https://commitfest.postgresql.org/patch/5588/ Много специалистов гетерогенным гистограммам, распределениям вероятностей, рисованию цветных планов, но... читать планы это не мешки ворочать код ревьювить.
Примеры реальных запросов 1С:ERP, которые приводились в докладе Антона Дорошкевича "Закрывай месяц в 1С ERP на PostgreSQL быстро и незаметно", а именно
запрос с Nested Loop на 482 секунды:
https://explain.tensor.ru/archive/explain/f76499ba8f4ff6f01f3c6a1d6f0121d0:0:2025-03-16
Запрос с Hash Join на 25 секунд:
https://explain.tensor.ru/archive/explain/1bc253be588285ae617c621001cb5759:0:2025-03-16

Результаты

На диаграмме приведена длительность запросов, выполняемых при закрытии месяца (большое число команд, обрабатывающих данные). Четыре левых столбика - версия PostgreSQL 16.8, четыре правых - версия PostgreSQL 17.4. На 17 версии закрытие месяца проходит в 2 раза быстрее. Это один из результатов доклада. Столбики (если считать слева направо) 1,2,3 и 5,6,7 сравнивают бесплатную сборку с PG Enterprise и PG Enterprise с включёнными расширениями Replan и AQE. Никакой разницы нет. Никакие ковыряния в планах, перепланирования не влияют на скорость выполнения запросов. Это же крамола! Разработчики бросают неимоверные усилия, пытаясь прикрутить логику поправления планировщика, а он ни в какую. Докладчик, конечно, сделал реверанс сказав, что на повседневной работе перепланирования и адаптации работают и ускоряют нажатие кнопки с 1 секунды до 0.5 секунды. Ирония в том, что частота нажатий кнопки примерно раз в 20 минут и пользователю кнопки в 1С абсолютно без разницы, будет ли нажатие работать 1 или даже 5 секунд. Человеку становится некомфортно и он начинает волноваться, подёргивать мышкой и терять осознанность спустя ~8 секунд после залипания кнопки. И тогда крутящееся колечко и "ваш клик очень важен для нас, оставайтесь на линии" не успокаивают.
Итак, столбики 1=2=3 и 5=6=7. А вот, столбик 4 существенно ниже столбиков 1=2=3. И самый правый столбик ниже трёх столбиков левее него. 4 и 8 столбики с подписью "Teodor" это сборки с "секретным патчем". Невооруженным (без лупы, но если дальнозоркость, то можно вооружиться) взглядом видно, что суммарное время выполнения запросов, выполняющихся при закрытии месяца в 1С уменьшается в 13066913/1688346=7.7 раз на 16 версии и в 7036026/1377187=5.1 раз на 17 версии.
Зачем нужны оранжевые столбики? Для оценки линейности изменений. Оранжевый столбик - длительность самого долгого запроса. Это 23 раза для PostgreSQL-16 и 16 раз для PostgreSQL-17. Это согласуется с тем, что чем больше число строк, тем более чревата ошибка в выборе Nested Loop вместо Hash Join.
Доклад также примечателен тем, что для теста выбрана реальная задача - суммарное время выполнения запросов, выполняющихся при "закрытии месяца" на реальных данных.
Немного о конференции
Конференция также интересна своей выставкой. Почему-то компаний на вставке было не много. Запомнился стенд Selectel, где все желающие могли собрать сервер на время:

Кто-нибудь узнал девушку, собирающую сервер? Если нет, то вы ничего не знаете про адаптивные планы.
Приятное впечатление оставил стенд Yadro, на котором за заполнение анонимной анкеты на планшете две девушки давали кубик-головоломку. Только во время заполнения анкеты я вспомнил, где я слышал про эту компанию - их железо будет в новой xData, подняв её производительность до невиданных iops. Кубиков можно купить самому пучок, но самостоятельно добытый трофей особенно ценен.
Хороших зелёных ручек, как год назад, в этот раз не раздавали. Не было стенда третьего форка PostgreSQL - Pangolinа, кончились днюжки режем косты. А я надеялся и ждал: хотел спросить, кто у них написал "Сценарии администрирования" - длиннющую простыню, которая мне понравилась. В прошлом году люди на их стенде мне понравились, просто и честно отвечали на вопросы. Но… непрофильный актив.
Был стенд с книжками по астрономии. Малоизвестно, но автор одной книги для детей Иван Панченко и можно было поймать автора и взять у него автограф. Ребенок у меня еще не читает, оставлю получение автографа на следующий раз. На другом стенде с книгами была представлена новейшая книга Моргунова - SQL-2, но я поленился её покупать, решив, что почитаю с сайта. Хотя нет, не поленился. Она стоила 1800, а книга Егора Рогова стоила 2000. При этом книга Егора Рогова в 2 раза увесистее во всех смыслах. Sic transit gloria mundi: метрика оценки книг вес/стоимость. 👐 Обе книги новейшие и их ещё нет в продаже, но электронные версии неизменно в свободном доступе. Бумажные версии обеих книги впервые продавались на этой конференции.
Модное слово этого сезона: больно. Интересно, где оно впервые появилось. 🤔 Слово аффектить почти отошло. Слово мультимодальный набирает обороты. Получится: «мультимодальность аффектит перформанс и делает больно».
Заключение
В статье раскрыт патч Фёдора Сигаева, благодаря которому закрытие месяца в 1С:ERP ускоряется на порядок. Также описана история нахождения патча и небольшой репортаж с конференции