Вопрос установки параметров сеанса при работе с СУБД PostgreSQL в документации 1С описан плохо, я нашёл только тут, да и то без должного акцента. Подумаешь, какие-то параметры при формировании плана. Почему-то этот вопрос отнесён к крупным внедрениям, а я считаю, что и для "мелких" он тоже актуален. Пока не разобрался, периодически ловил "тупняки" с тем, что не получается воспроизвести выполнение долгого запроса непосредственно через SQL. Время выполнения запроса в 1С и в PGAdmin разное, но так же не может быть (я пример ниже приведу).
Уважаемые ресурсы также не акцентируют внимание на необходимости дополнительных параметров при построении плана запроса. Например, на сайте Гилёва, посвящённому настройке PostgreSQL, этот вопрос не учтён и указаны рекомендуемые значения переменных, которые потом перезаписываются сервером при соединении.
Посмотрим, что реально происходит при соединении.
Экспериментируем на виртуальной машине под Windows 10, версия платформы 8.3.23.2114, версия СУБД 15.6 от Postgres Pro. Порядок проведения эксперимента:
- сервер 1С остановлен;
- подключаем технологический журнал с отбором по событию DBPOSTGRS;
- запускаем сервер;
- подключаемся к любой базе (не важно, конфигуратор или предприятие);
- закрываем 1С;
- останавливаем службу сервера.
Открываем папочку с логами, нас интересует лог рабочего процесса rphost_XXXX и смотрим в самом верху команды, которые выполняет сервер 1С при подключении к базе.
Видим, что сервер 1С устанавливает какие-то параметры для текущей сессии на сервере PostgreSQL. Интересно, какие. Информацию о параметрах буду брать с сайта Postgres Pro
SET client_min_messages=error
Переменная client_min_messages управляет минимальным уровнем сообщений, посылаемых клиенту. Допустимые значения DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1, LOG, NOTICE, WARNING и ERROR. Каждый из перечисленных уровней включает все идущие после него. Чем дальше в этом списке уровень сообщения, тем меньше сообщений будет посылаться клиенту. По умолчанию используется NOTICE.
Т.е. в нашем случае с СУБД на сервер 1С будет направляться только информация по ошибкам.
SET lc_messages to 'en_US.UTF-8'
Установка языка сообщений, тут вопросов нет.
SET enable_mergejoin = off
Переменная enable_mergejoin включает или отключает использование планов соединения слиянием. По умолчанию имеет значение on (вкл.).
А вот это важный момент. Дело в том, что у СУБД PostgreSQL есть 3 способа соединения таблиц, они отличаются временем на подготовку и скоростью работы (см. рисунок) и тут 1С берёт и отключает один из способов. При формировании плана запроса нужно обязательно учитывать этот нюанс.
SET escape_string_warning = off
Этот параметр влияет на поведение при использовании экранирующего символа «\». Сервер 1С отключает предупреждение при наличии этого символа в строках.
SET cpu_operator_cost = 0.001
Этот параметр задаёт приблизительную стоимость обработки оператора или функции при выполнении запроса. Не буду углубляться в нюансы работы оптимизатора, но отмечу, что в СУБД PostgreSQL все операции что-то «стоят» и планировщик строит несколько планов и выбирает из них самый «дешевый». Базовой единицей стоимости считается seq_page_cost, т.е. время на чтение одной страницы с диска при последовательном чтении. Соответственно выполнение оператора процессором получается в 1000 раз быстрее, чем последовательное чтение. По умолчанию этот параметр равен 0.0025, т.е. выполнение операций процессором в 400 раз быстрее чтения с диска.
А вот теперь представим ситуацию, вы с помощью параметра log_min_duration_statement протоколируете долгие запросы. И вот найден запрос, вы его выполняете в PGAdmin и получаете совершенно другое время выполнения. В итоге всё списывается на неактуальность статистики, но задача не решается. А причина в том, что планировщик работает не с тем значением стоимости, которая установлена в параметрах сервера, а с другим, в 4 раза меньшим и строит разные планы выполнения с разным временем.
SET client_encoding = 'utf8'
Устанавливается кодировка клиента.
SET lock_timeout = 20000
Хотел написать, что это время ожидания при конфликте взаимоблокировок, которое указывается в настройке базы в конфигураторе, но я не нашёл такого параметра в документации deadlock_timeout есть, а lock_timeout - нет.
Выводы
Для получения корректного плана запроса не забываем дополнять SQL следующими параметрами:
/* Параметры соединения платформы */
SET client_min_messages=error;
SET lc_messages to 'en_US.UTF-8';
SET enable_mergejoin = off;
SET escape_string_warning = off;
SET cpu_operator_cost = 0.001;
set client_encoding = 'utf8';
SET lock_timeout = 20000;
SET track_io_timing = TRUE;
EXPLAIN (ANALYZE, BUFFERS)
SELECT ...