1С и Postgres: первый серьезный опыт борьбы и противостояния, постигаем open source

0. shakun_dg 106 27.02.23 11:00 Сейчас в теме
А все начиналось с распространенной для этой связки проблемы закрытия месяца…

Перейти к публикации

Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. ansverrr 27.02.23 15:21 Сейчас в теме
Ничего не понятно, но очень интересно! По общему впечатлению - отличный материал для 1С:Эксплуататоров. Авторы статьи - герои. Которых мы не заслужили, но в которых нуждались. :)
maksa2005; user1738719; Stref75; sapervodichka; +4 Ответить
2. sapervodichka 6465 27.02.23 15:30 Сейчас в теме
(1) одни подводные камни - значит пришло время пересаживаться с лодки на подлодку )
3. user1915184 27.02.23 16:18 Сейчас в теме
Взял из open source - верни в open source. Золотое правило.
Не поленитесь еще теперь по своим доработкам прислать пулл реквест в репу https://github.com/postgres/postgres/pulls чтобы поддержать комьюнити. Наверняка его сразу не примут и потребуется немного постараться, но оно того стоит!

Спасибо за очередную статью, подтверждающую что не "PG плохой, MSSQL хороший", а всего лишь надо заниматься оптимизацией запросов (как и в любом другом фреймворке).
Shmell; check2; bilex; q_i; rintik; pavlov_dv; Dach; siliconvalet; leongl; ixijixi; +10 Ответить
24. ivanov660 3895 28.02.23 20:20 Сейчас в теме
(3) Текущая ссылка на зеркало, через него они не принимают PR. Как отправить изменения читаем тут: https://wiki.postgresql.org/wiki/Submitting_a_Patch.
4. ptr128 27.02.23 16:18 Сейчас в теме
А не проще ли создавать индексы на временных таблицах. Или даже изначально использовать постоянные нежурналируемые таблицы с нужными индексами, вместо временных?
8. shakun_dg 106 28.02.23 08:11 Сейчас в теме
(4) Можно по-разному решить проблему, но так или иначе придется лезть в типовое решение и в дальнейшем поддерживать и обслуживать все свои доработки. А лезть в закрытие месяца не очень то и хочется)
11. ptr128 28.02.23 10:55 Сейчас в теме
(8) Вот более развернутый пример, для понимания того, как можно не трогая типовое решение индексировать временные таблицы:
Код на SQL


P.S. Не знаю, почему форум пробелы вставляет куда ни попадя. Победить не удалось (
5. denacid 91 27.02.23 16:29 Сейчас в теме
(1) Герои не носят плащи, герои пишут на СИ)
16. starik-2005 2834 28.02.23 15:33 Сейчас в теме
(5)
герои пишут на СИ
Все приличные студенты ИТ-ники ныне возведены в ранг героя. Я ожидал чего-то подобного, но не так скоро...
6. vazelin 114 27.02.23 17:25 Сейчас в теме
Если правильно понял, свое расширение для постгрес было написано для полусения отборов по планам. А если включить техрурнал с отбором по базе и тегом plansql?
7. shakun_dg 106 28.02.23 08:01 Сейчас в теме
(6) ИМХО удобней использовать и проще контролировать прямые и родные для СУБД инструменты. Техжурнал тот еще посредник.
9. anosin 30 28.02.23 08:49 Сейчас в теме
(6) техжурнал тебе не посоветует индекса по собранной статистике.
10. ptr128 28.02.23 10:15 Сейчас в теме
(8) Не надо лезть в типовое решение. Подобная заплатка реализуема средствами СУБД через event trigger на создание временной таблицы
12. ivanov660 3895 28.02.23 12:11 Сейчас в теме
Не согласен с выводом
Loop join ожидает, что будет 1 строка, а получает 39 тысяч строк, отчего надолго «уходит в себя», так как на временной таблице нет индекса и приходится идти в скан (Seq Scan), а там около 200 тысяч строк.

Тут скорее речь идет о статистике и о том что postgres через несколько соединений плохо справляется с предсказанием, поэтому считая что будет мало строк выбирает Nested Loop.
(Для пересчета статистики по временным таблицам есть плагин online_analyze (online_analyze.table_type = 'temporary' включать только так), но не уверен что поможет.)
Удобнее было бы реализовать что-то вроде AQO или взять его, т.е. исправлять похожие "кривые" планы. Я бы не рекомендовал использовать глобальное отключение использования nested loop.
Gilev.Vyacheslav; +1 Ответить
15. shakun_dg 106 28.02.23 13:17 Сейчас в теме
(12) online_analyze.table_type = 'temporary' так и настроено и PG прекрасно видит количество строк на временных таблицах, но после нескольких отборов оптимизатор говорит что будет 1 строка, и как следствие выбирает loop для соединения, который, к сожалению, получает 39 тысяч строк.
17. ptr128 28.02.23 16:18 Сейчас в теме
(12) Тут проблема у PostgreSQL. Статистику для временной таблицы построит или обновит VACUUM, но когда это он сделает - неизвестно. Может через секунду, а может и через час. Когда доберется до нее и как загрузка сервера позволит. Поэтому и рекомендуется после заполнения временной таблицы явно из кода запускать на нее ANALYZE.
С другой стороны, и на MS SQL я встречал изрядные тормоза, когда забывали проиндексировать временную таблицу. Поэтому индексировать временную таблицу стоит всегда, за исключением тех случаев, когда все равно по ней нужно только полное сканирование. Например, когда она затем будет использована только в FR OM без WH ERE и все остальные таблицы в JOIN имеют подходящие индексы.
С рекомендацией не использовать глобальное отключение NESTED LOOP - полностью согласен.
А вот решение, которое я применял, считаю предпочтительным. А именно, как уже писал выше, индексировать временные таблицы при их создании средствами событийного триггера, не трогая конфигурацию 1С.
18. ivanov660 3895 28.02.23 16:32 Сейчас в теме
(17)Читаем документацию модуля online_analyze https://postgrespro.ru/docs/postgrespro/15/online-analyze

Модуль online_analyze предоставляет набор функций, которые немедленно обновляют статистику после операций INSERT, UPDATE, DELETE или SELECT INTO в целевых таблицах.


т.е. отвечая на ваш вопрос - сделает сразу (если включите, конечно), модуль встроен ребятами из Postgres Pro.
Gilev.Vyacheslav; +1 Ответить
19. ptr128 28.02.23 16:48 Сейчас в теме
(18)
(18)
online_analyze

А я про этот костыль и не упоминал. У него есть целый ряд других проблем, из-за чего online_analyze и не принят в mainstreem. Навскидку:
1. Каждый DML запрос, обновляющий таблицу, ожидает завершение обновления ее статистик.
2. У автора (Сигаева) даже в планах нет использовать background worker.
3. При откате транзакции статистика не откатывается, что в последствии может привести к непредсказуемому поведению планировщика запросов.
siliconvalet; +1 1 Ответить
20. ivanov660 3895 28.02.23 16:56 Сейчас в теме
(19)
Костыль один, костыль другой - это да проблема. Но пока я не видел альтернативных удобных плагинов потсгре.
Кстати пишут, что
начиная с версии 8.3.13, платформа 1С самостоятельно включает использование analyze явным образом после вставки во временную таблицу
https://it-expertise.ru/blog/records/parametr-online-analyze-postgresql-vs-1c-predpriyatie-8/
21. ptr128 28.02.23 17:10 Сейчас в теме
(20)
Ну так про явный вызов ANALYZE я и писал выше. Но радикальное решение проблемы ТС, повторюсь, в индексации временной таблицы при ее создание событийным триггером. И эффект от этого будет существенно выше, чем от статистик по неиндексированной таблице, заставляющих, по сути, СУБД строить хеш индекс таблицы в памяти при каждом запросе, обращающемся к ней.
И это еще если JOIN по равенству полей. А если нет? HASH JOIN тогда и не поможет. А правильный индекс - еще как поможет.
22. shakun_dg 106 28.02.23 18:23 Сейчас в теме
(21) 1С рандомно генерирует имя временной таблицы при выполнении запроса, имена полей тоже не исключение, хоть и зависят от порядка в тексте запроса 1С. Про составные поля и говорить не стоит. Такое отлавливать триггером в PG так себе занятие, проще уже индекс средствами 1С накинуть раз уж на то пошло.
Gilev.Vyacheslav; +1 Ответить
23. ptr128 28.02.23 19:39 Сейчас в теме
(22)
Если через ПОМЕСТИТЬ, то по счетчику. Но нам или важна структура таблицы, или только одно поле, с именем заканчивающимся на RRef. А уж проверить структуру таблицы в триггере, если уж очень хочется - не проблема. Мне до структуры доходить редко приходилось. Чаще, триггером индексирую первое поле, имя которого заканчивается на RRef, чего уже хватает.

Про проще, не знаю. В случае ПОМЕСТИТЬ, это уж точно код править. Лично мне проще на plpgsql один раз функцию написать, чем после каждого обновления патчить типовую конфигурацию.
25. shakun_dg 106 28.02.23 21:06 Сейчас в теме
(23)
Чаще, триггером индексирую первое поле, имя которого заканчивается на RRef

Как определяете какую именно временную таблицу индексировать?
26. ptr128 28.02.23 22:08 Сейчас в теме
(25) А я и точно и не определял. Если создается временная таблица с нужным мне количеством полей и первым полем, заканчивающимся на RRef - я по нему и индексировал. С одной стороны, на индексации каких-то лишних таблиц я терял секунды. Но с другой стороны, при закрытии выигрывал часы.
27. shakun_dg 106 01.03.23 07:49 Сейчас в теме
(26) Если то самое первое RRef никак не участвует ни в отборах ни в соединениях, и по факту надо индексировать какое-нибудь 3 или 4 по счету RRef, то такую ситуацию как то дополнительно обрабатывали? или просто не было нужды?
Количество полей временной таблицы тоже вещь не постоянная, легко может поменяться запрос в новом релизе, соответственно придется править триггер. Ну или поле было не составным, а стало составным (или на оборот), а с виду запрос 1С и не менялся, то тоже надо править триггер. Получается что все равно надо следить и контролировать.
28. ptr128 01.03.23 13:51 Сейчас в теме
(27)
Редко, но бывают ситуации, когда приходится анализировать не только количество, но и типы, длины и порядок всех полей таблицы. Благо метаданные таблицы доступны.
Саму информацию о временных таблицах и их метаданных собираю такой функцией на событийном триггере:
CREATE OR REPLACE FUNCTION catch_tmp_tables_info()
RETURNS event_trigger LANGUAGE plpgsql AS $func$
DECLARE
  obj record;
  metadata text;
BEGIN
    FOR obj IN
      SEL ECT *
      FR OM pg_event_trigger_ddl_commands()
      WHERE object_type='table' AND schema_name='pg_temp'
    LOOP
      SELECT STRING_AGG(attname||$$,$$||attnum::varchar||$$,$$||atttypid::varchar
          ||$$($$||attlen::varchar||$$,$$||atttypmod::varchar||$$) $$||attnotnull::varchar,$$;$$)
      FR OM pg_attribute
      WH ERE attrelid=obj.objid AND attnum>0
      INTO metadata;
      
      RAISE NOTICE '% ddl commands: % "%"', tg_tag, obj.object_identity, metadata;
    END LOOP;
END;
$func$;
Показать

А то, что после нового релиза может как появится новая проблема, так и решиться имеющаяся - это уже жизнь. От этого мы никуда не денемся.
13. mixsture 28.02.23 12:30 Сейчас в теме
Даже по имени базы.
...
А если это общий сервер для тестирования и там много баз?


Имхо, тут постгрес идеологически по-другому подходит. С позиции 1 инстанс = 1 база. Обратное, хоть теоретически и возможно, но убивает полностью процесс бекапов/восстановления в двоичном виде.
Shmell; ptr128; +2 Ответить
14. ValeraEm 138 28.02.23 13:04 Сейчас в теме
Зачем отбор по имени базы? Это не актуально. Для базы приложения отдельный сервер в отдельном контейнере и вся заточка под конкретный кейс.
Shmell; ptr128; +2 Ответить
29. check2 304 13.04.23 12:12 Сейчас в теме
Коллеги, я же правильно понял, что вы использовали Postgres из дистрибутивов 1С? А PostgresPro Std/Ent не пробовали?
Было бы полезно знать есть ли такие болячки в pgpro.
30. shakun_dg 106 13.04.23 14:41 Сейчас в теме
(29) Использовали только от 1С, другие дистрибутивы не юзали
Оставьте свое сообщение
Вакансии
Начальник отдела программирования
Уфа
зарплата от 125 000 руб.
Полный день

Программист/тестировщик
Москва
зарплата от 130 000 руб. до 150 000 руб.
Полный день

Ведущий разработчик 1С / Team lead отдела разработки 1С
Москва
зарплата от 300 000 руб. до 300 000 руб.
Полный день

Программист 1С
Москва
зарплата от 130 000 руб. до 150 000 руб.
Полный день

Бизнес-аналитик
Москва
зарплата от 130 000 руб. до 150 000 руб.
Полный день