F.4. auto_dump — расширение с хуком ProcessInterrupts#

F.4. auto_dump — расширение с хуком ProcessInterrupts

F.4. auto_dump — расширение с хуком ProcessInterrupts #

F.4.1. Обзор #

auto_dump помогает вам создать самодостаточную репродукцию проблемных запросов, которые выполняются в рабочей среде (например, из 1С).

Когда условие триггера выполняется, расширение записывает:

  • DDL для таблиц, используемых в запросе (временных и/или постоянных — настраиваемо)

  • Необязательные дампы данных (операторы INSERT)

  • Необязательные команды создания индексов

  • Необязательный текст запроса

  • Необязательный план(ы) выполнения: EXPLAIN и EXPLAIN (ANALYZE, BUFFERS, WAL, TIMING, SUMMARY)

Дампы записываются в каталог, создаваемый для каждого запроса и называемый:

<PID>-YYYY_MM_DD_hh_mm_ss-<counter>/

Пример файлов:

create.sql
createwithdata.sql

Примечание

Планирование дампа и триггер dump_on_cancel требуют небольшего патча ядра, который добавляет ProcessInterrupts_hook. Для работы этих функций необходимо применить этот патч и собрать Tantor SE с ним.

F.4.2. Требования #

  • Tantor SE версии, соответствующей патчам/исходным кодам, с которыми вы производите сборку.

  • C-инструментарий для сборки расширений Tantor SE.

  • Основной патч (добавляет ProcessInterrupts_hook), если хотите:

    • dump-on-cancel (auto_dump.dump_on_cancel)

    • сбор плана с инструментированием (auto_dump.dump_plan = on или auto_dump.dump_on_bad_plan = on)

F.4.3. Включение расширения #

  1. Добавьте в postgresql.conf (для всего кластера):

    shared_preload_libraries = 'auto_dump'
    auto_dump.enable = on
    auto_dump.output_directory = '/var/lib/postgresql/auto_dump_files/'
    
  2. Перезапустите Tantor SE:

    systemctl restart tantor-se-server-16
    
  3. В целевой базе данных:

    CREATE EXTENSION auto_dump;
    

F.4.4. Конфигурация (GUCs) #

Все параметры GUC имеют значение SUSET (могут быть установлены суперпользователем во время выполнения, если не указано иное ограничение). Значения по умолчанию соответствуют текущей реализации в коде.

F.4.4.1. Основные параметры (GUC) #

GUC Тип Значение по умолчанию Описание
auto_dump.enable bool off Главный GUC для включения дампирования.
auto_dump.output_directory string '' Каталог, в котором создаются папки дампов (обязательно).
auto_dump.dump_query bool on Включает исходный текст запроса (в виде блока комментария).
auto_dump.dump_create bool on Включает операторы создания таблиц.
auto_dump.dump_indexes bool on Включает операторы создания индексов.
auto_dump.dump_data bool on Включает данные таблицы (INSERT).
auto_dump.dump_plan bool on Включает вывод EXPLAIN и EXPLAIN ANALYZE. Требуется инструментирование.

F.4.4.2. Параметры сохранения таблиц #

GUC Тип Значение по умолчанию Описание
auto_dump.dump_temporary_tables bool true Сохраняет временные таблицы, на которые ссылается запрос.
auto_dump.dump_persistent_tables bool false Сохраняет постоянные таблицы, на которые ссылается запрос.
auto_dump.dump_all_temp_tables bool false Сохраняет все временные таблицы в текущей сессии backend, а не только те, которые были использованы в запросе, вызвавшем триггер.

F.4.4.3. Триггеры #

GUC Тип Значение по умолчанию Описание
auto_dump.dump_on_query_string string '' Если не пусто, выполняет дамп, когда текст запроса содержит эту подстроку или подстроки.
auto_dump.dump_on_cancel bool false Выполняет дамп при отмене текущего запроса. Требует патча ядра (добавляет ProcessInterrupts_hook).
auto_dump.dump_on_bad_plan bool false Выполняет дамп, когда выполненный план считается плохим (см. пороги ниже). Требуется инструментирование.
F.4.4.3.1. dump_on_query_string: несколько подстрок с | #

Вы можете указать несколько альтернатив для подстроки-триггера, разделяя их вертикальной чертой (|):

CREATE TABLE AAA(BBB int, CCC int);

SET auto_dump.dump_on_query_string = 'AAA';
-- Triggers (contains 'AAA') - default work
SELECT 1 FROM AAA;

SET auto_dump.dump_on_query_string = 'AAA|BBB|CCC';

-- Triggers (contains 'AAA' or 'BBB' or 'CCC')
SELECT 1 FROM AAA;
SELECT BBB FROM AAA;
-- Does not trigger (different case):
SELECT ccc FROM aaa;

-- To match case variants, list them explicitly:
SET auto_dump.dump_on_query_string = 'AAA|BBB|CCC|aaa|bbb|ccc';

F.4.4.4. Пороговые значения "плохого плана" #

Узел плана считается плохим только если оба включённых порога превышены (логическое И). Вы можете отключить порог, установив его в значение 0 или ниже.

GUC Тип Значение по умолчанию Значение
auto_dump.bad_plan_count_threshold int 0 Абсолютная разница между оценочным и фактическим количеством строк для срабатывания. > 0 включает; <= 0 отключает.
auto_dump.bad_plan_percent_threshold int 0 Процентное различие для срабатывания. > 0 включает; <= 0 отключает. Процент вычисляется только если estimated > 0, чтобы избежать деления на ноль.
auto_dump.bad_plan_min_expected_rows int 100 Минимальный порог оценочного количества строк. Узлы, у которых как оценочное, так и фактическое количество строк ниже порога, игнорируются (подавление шума).
auto_dump.bad_plan_min_actual_rows int 100 Минимальное фактическое количество строк (используется вместе с порогом оценочного количества строк).

Примечание

На загруженных рабочих нагрузках 1С, начните с:

auto_dump.dump_on_bad_plan = on
auto_dump.bad_plan_min_expected_rows = 100
auto_dump.bad_plan_min_actual_rows   = 100
auto_dump.bad_plan_count_threshold   = 1000
auto_dump.bad_plan_percent_threshold = 300

Если в запросах часто встречается estimate = 0, и вы всё равно хотите реагировать на большие абсолютные несоответствия, отключите порог в процентах:

auto_dump.bad_plan_percent_threshold = 0

F.4.5. Режимы срабатывания #

  • По подстроке: если auto_dump.dump_on_query_string является непустой строкой и текст запроса содержит её, создаётся дамп.

  • При отмене: если auto_dump.dump_on_cancel = on, дамп создаётся, когда pg_cancel_backend() прерывает выполняющийся запрос (требуется патч ядра с ProcessInterrupts_hook).

  • При плохом плане: если auto_dump.dump_on_bad_plan = on, исполнитель проверяет счетчики инструментирования после выполнения и срабатывает, если пороги превышены.

F.4.6. Что выгружается #

  • create.sql: объекты схемы (таблицы, индексы), ANALYZE, и — в блоке комментария — текст EXPLAIN, если dump_plan = on и EXPLAIN был запрошен без данных.

  • createwithdata.sql: то же, что и create.sql, плюс операторы INSERT с сохранёнными строками (когда dump_data = on).

  • Исходный текст запроса включается в виде блока комментария, когда dump_query = on.

По умолчанию только временные таблицы выгружаются (auto_dump.dump_temporary_tables = on, auto_dump.dump_persistent_tables = off). Включите сохранение постоянных таблиц, если вам нужно полностью воспроизвести ситуацию вне исходной сессии.

F.4.7. Каталог вывода и наименование файлов #

  • Базовый каталог: auto_dump.output_directory (должен быть доступен для записи пользователем операционной системы сервера базы данных).

  • Каждая выгрузка создает подкаталог:

    <PID>-YYYY_MM_DD_hh_mm_ss-<counter>/
    
  • Файлы внутри:

    create.sql
    createwithdata.sql
    

F.4.8. Пример использования (из реальной нагрузки, похожей на 1С) #

У нас есть SQL-запрос, который нам нужно воспроизвести и отладить:

SELECT
T1._Q_000_F_001RRef,
T1._Q_000_F_002RRef,
CASE WHEN (T1._Q_000_F_003RRef IN ('\\261\\321\\276\\257\\272\\331\\300wM\\263\\336*q\\031I\\316'::bytea, '\\247\\202\\266$\\366\\301r\\343N\\300\\333\\\\m1\\221\\330'::bytea, '\\235\\352S\\336\\242/$\\372L\\011\\237\\202K\\246\\332n'::bytea)) THEN SUM(T2._Fld33213) WHEN (T1._Q_000_F_003RRef IN ('\\200\\357\\030o\\256\\333\\332W@\\263\\231\\3626\\013\\334t'::bytea)) THEN SUM(T4._Fld33309) END,
T1._Q_000_F_000RRef
FROM pg_temp.tt7 T1
LEFT OUTER JOIN _Document1328_VT33208X1 T2
LEFT OUTER JOIN _Document1328X1 T3
ON (T2._Document1328_IDRRef = T3._IDRRef) AND (T3._Fld2488 = CAST(0 AS NUMERIC))
ON ((T1._Q_000_F_000RRef = T3._Fld33135RRef) AND (T1._Q_000_F_001RRef = T2._Fld33210RRef) AND (T1._Q_000_F_002RRef = T2._Fld33211RRef) AND (T2._Fld33240 = FALSE)) AND (T2._Fld2488 = CAST(0 AS NUMERIC))
LEFT OUTER JOIN _Document1328_VT33302X1 T4
LEFT OUTER JOIN _Document1328X1 T5
ON (T4._Document1328_IDRRef = T5._IDRRef) AND (T5._Fld2488 = CAST(0 AS NUMERIC))
ON ((T1._Q_000_F_000RRef = T5._Fld33135RRef) AND (T1._Q_000_F_001RRef = T4._Fld33304RRef) AND (T1._Q_000_F_002RRef = T4._Fld33305RRef) AND (T4._Fld77517 = FALSE)) AND (T4._Fld2488 = CAST(0 AS NUMERIC))
GROUP BY T1._Q_000_F_000RRef,
T1._Q_000_F_003RRef,
T1._Q_000_F_001RRef,
T1._Q_000_F_002RRef;

В postgresql.conf включите расширение, укажите каталог для дампов и задайте подстроку, которая должна вызывать дамп для этого запроса:

shared_preload_libraries = 'auto_dump'
auto_dump.enable = on
auto_dump.output_directory = '/var/lib/postgresql/auto_dump_files/'
auto_dump.dump_on_query_string = 'LEFT OUTER JOIN _Document1328_VT33208X1 T2'

Перезапустите службу Tantor SE:

systemctl restart tantor-se-server-16

Создайте расширение в базе данных, в которой выполняется целевой запрос:

-- psql
\c erp
CREATE EXTENSION auto_dump;

После того как пользователь в 1С инициирует бизнес-действие, запускающее запрос, в каталоге /var/lib/postgresql/auto_dump_files/ появляется новый подкаталог:

/var/lib/postgresql/auto_dump_files/984933-2025_10_30_15_08_04_04/

Файлы в этом каталоге:

-rw------- 1 postgres postgres 12906 Oct 30 15:08 create.sql
-rw------- 1 postgres postgres 13290 Oct 30 15:08 createwithdata.sql

Различие между файлами:

  • create.sql – DDL (и комментарии с зафиксированным запросом/планом, если включено)

  • createwithdata.sql – всё, что находится в create.sql плюс INSERT операторы с сохранёнными строками

По умолчанию только временные таблицы выгружаются (auto_dump.dump_temporary_tables = on). Вы увидите данные, подобные следующим:

CREATE TEMPORARY TABLE tt7 (
    _q_000_f_000rref bytea,
    _q_000_f_001rref bytea,
    _q_000_f_002rref bytea,
    _q_000_f_003rref bytea,
    _q_000_f_004 numeric(10,0),
    _q_000_f_005 timestamp without time zone,
    _q_000_f_006 timestamp without time zone,
    _q_000_f_007 timestamp without time zone
);

CREATE INDEX tmpind_0 ON pg_temp.tt7 USING btree (_q_000_f_000rref);INSERT INTO tt7 (_q_000_f_000rref, _q_000_f_001rref, _q_000_f_002rref, _q_000_f_003rref, _q_000_f_004, _q_000_f_005, _q_000_f_006, _q_000_f_007) VALUES (E'\\x98891866dab152db11eedf71f5f2a486',E'\\x83b11866dab152db11ee95becd03e9a6',E'\\x00000000000000000000000000000000',E'\\xb1d1beafbad9c0774db3de2a711949ce',0,'2024-03-12 00:00:00','2024-03-13 00:00:00','2024-03-12 00:00:00');

ANALYZE tt7;
/*
SELECT
T1._Q_000_F_001RRef,
T1._Q_000_F_002RRef,
CASE WHEN (T1._Q_000_F_003RRef IN ('\261\321\276\257\272\331\300wM\263\336*q\031I\316'::bytea, '\247\202\266$\366\301r\343N\300\333\\m1\221\330'::bytea, '\235\352S\336\242/$\372L\011\237\202K\246\332n'::bytea)) THEN SUM(T2._Fld33213) WHEN (T1._Q_000_F_003RRef IN ('\200\357\030o\256\333\332W@\263\231\3626\013\334t'::bytea)) THEN SUM(T4._Fld33309) END,
T1._Q_000_F_000RRef
FROM pg_temp.tt7 T1
LEFT OUTER JOIN _Document1328_VT33208X1 T2
LEFT OUTER JOIN _Document1328X1 T3
ON (T2._Document1328_IDRRef = T3._IDRRef) AND (T3._Fld2488 = CAST(0 AS NUMERIC))
ON ((T1._Q_000_F_000RRef = T3._Fld33135RRef) AND (T1._Q_000_F_001RRef = T2._Fld33210RRef) AND (T1._Q_000_F_002RRef = T2._Fld33211RRef) AND (T2._Fld33240 = FALSE)) AND (T2._Fld2488 = CAST(0 AS NUMERIC))
LEFT OUTER JOIN _Document1328_VT33302X1 T4
LEFT OUTER JOIN _Document1328X1 T5
ON (T4._Document1328_IDRRef = T5._IDRRef) AND (T5._Fld2488 = CAST(0 AS NUMERIC))
ON ((T1._Q_000_F_000RRef = T5._Fld33135RRef) AND (T1._Q_000_F_001RRef = T4._Fld33304RRef) AND (T1._Q_000_F_002RRef = T4._Fld33305RRef) AND (T4._Fld77517 = FALSE)) AND (T4._Fld2488 = CAST(0 AS NUMERIC))
GROUP BY T1._Q_000_F_000RRef,
T1._Q_000_F_003RRef,
T1._Q_000_F_001RRef,
T1._Q_000_F_002RRef;*/
/*
Query Text: SELECT
T1._Q_000_F_001RRef,
T1._Q_000_F_002RRef,
CASE WHEN (T1._Q_000_F_003RRef IN ('\\261\\321\\276\\257\\272\\331\\300wM\\263\\336*q\\031I\\316'::bytea, '\\247\\202\\266$\\366\\301r\\343N\\300\\333\\\\m1\\221\\330'::bytea, '\\235\\352S\\336\\242/$\\372L\\011\\237\\202K\\246\\332n'::bytea)) THEN SUM(T2._Fld33213) WHEN (T1._Q_000_F_003RRef IN ('\\200\\357\\030o\\256\\333\\332W@\\263\\231\\3626\\013\\334t'::bytea)) THEN SUM(T4._Fld33309) END,
T1._Q_000_F_000RRef
FROM pg_temp.tt7 T1
LEFT OUTER JOIN _Document1328_VT33208X1 T2
LEFT OUTER JOIN _Document1328X1 T3
ON (T2._Document1328_IDRRef = T3._IDRRef) AND (T3._Fld2488 = CAST(0 AS NUMERIC))
ON ((T1._Q_000_F_000RRef = T3._Fld33135RRef) AND (T1._Q_000_F_001RRef = T2._Fld33210RRef) AND (T1._Q_000_F_002RRef = T2._Fld33211RRef) AND (T2._Fld33240 = FALSE)) AND (T2._Fld2488 = CAST(0 AS NUMERIC))
LEFT OUTER JOIN _Document1328_VT33302X1 T4
LEFT OUTER JOIN _Document1328X1 T5
ON (T4._Document1328_IDRRef = T5._IDRRef) AND (T5._Fld2488 = CAST(0 AS NUMERIC))
ON ((T1._Q_000_F_000RRef = T5._Fld33135RRef) AND (T1._Q_000_F_001RRef = T4._Fld33304RRef) AND (T1._Q_000_F_002RRef = T4._Fld33305RRef) AND (T4._Fld77517 = FALSE)) AND (T4._Fld2488 = CAST(0 AS NUMERIC))
GROUP BY T1._Q_000_F_000RRef,
T1._Q_000_F_003RRef,
T1._Q_000_F_001RRef,
T1._Q_000_F_002RRef
GroupAggregate  (cost=5.02..5.04 rows=1 width=100)
  Group Key: t1._q_000_f_000rref, t1._q_000_f_003rref, t1._q_000_f_001rref, t1._q_000_f_002rref
  ->  Sort  (cost=5.02..5.02 rows=1 width=78)
        Sort Key: t1._q_000_f_000rref, t1._q_000_f_003rref, t1._q_000_f_001rref, t1._q_000_f_002rref
        ->  Nested Loop Left Join  (cost=0.73..5.00 rows=1 width=78)
              ->  Nested Loop Left Join  (cost=0.39..3.41 rows=1 width=73)
                    ->  Seq Scan on tt7 t1  (cost=0.00..1.01 rows=1 width=68)
                    ->  Nested Loop  (cost=0.39..2.39 rows=1 width=56)
                          Join Filter: ((t1._q_000_f_001rref = t4._fld33304rref) AND (t1._q_000_f_002rref = t4._fld33305rref))
                          ->  Index Only Scan using _document1328_4x1 on _document1328x1 t5  (cost=0.17..1.29 rows=1 width=34)
                                Index Cond: ((_fld2488 = '0'::numeric) AND (_fld33135rref = t1._q_000_f_000rref))
                          ->  Index Scan using _document1328_vt33302_skx1 on _document1328_vt33302x1 t4  (cost=0.22..0.93 rows=14 width=56)
                                Index Cond: ((_fld2488 = '0'::numeric) AND (_document1328_idrref = t5._idrref))
                                Filter: (NOT _fld77517)
              ->  Nested Loop  (cost=0.34..1.58 rows=1 width=56)
                    Join Filter: ((t1._q_000_f_001rref = t2._fld33210rref) AND (t1._q_000_f_002rref = t2._fld33211rref))
                    ->  Index Only Scan using _document1328_4x1 on _document1328x1 t3  (cost=0.17..1.29 rows=1 width=34)
                          Index Cond: ((_fld2488 = '0'::numeric) AND (_fld33135rref = t1._q_000_f_000rref))
                    ->  Index Scan using _document1328_vt33208_skx1 on _document1328_vt33208x1 t2  (cost=0.17..0.28 rows=1 width=56)
                          Index Cond: ((_fld2488 = '0'::numeric) AND (_document1328_idrref = t3._idrref))
                          Filter: (NOT _fld33240)
*/
/*
Query Text: SELECT
T1._Q_000_F_001RRef,
T1._Q_000_F_002RRef,
CASE WHEN (T1._Q_000_F_003RRef IN ('\\261\\321\\276\\257\\272\\331\\300wM\\263\\336*q\\031I\\316'::bytea, '\\247\\202\\266$\\366\\301r\\343N\\300\\333\\\\m1\\221\\330'::bytea, '\\235\\352S\\336\\242/$\\372L\\011\\237\\202K\\246\\332n'::bytea)) THEN SUM(T2._Fld33213) WHEN (T1._Q_000_F_003RRef IN ('\\200\\357\\030o\\256\\333\\332W@\\263\\231\\3626\\013\\334t'::bytea)) THEN SUM(T4._Fld33309) END,
T1._Q_000_F_000RRef
FROM pg_temp.tt7 T1
LEFT OUTER JOIN _Document1328_VT33208X1 T2
LEFT OUTER JOIN _Document1328X1 T3
ON (T2._Document1328_IDRRef = T3._IDRRef) AND (T3._Fld2488 = CAST(0 AS NUMERIC))
ON ((T1._Q_000_F_000RRef = T3._Fld33135RRef) AND (T1._Q_000_F_001RRef = T2._Fld33210RRef) AND (T1._Q_000_F_002RRef = T2._Fld33211RRef) AND (T2._Fld33240 = FALSE)) AND (T2._Fld2488 = CAST(0 AS NUMERIC))
LEFT OUTER JOIN _Document1328_VT33302X1 T4
LEFT OUTER JOIN _Document1328X1 T5
ON (T4._Document1328_IDRRef = T5._IDRRef) AND (T5._Fld2488 = CAST(0 AS NUMERIC))
ON ((T1._Q_000_F_000RRef = T5._Fld33135RRef) AND (T1._Q_000_F_001RRef = T4._Fld33304RRef) AND (T1._Q_000_F_002RRef = T4._Fld33305RRef) AND (T4._Fld77517 = FALSE)) AND (T4._Fld2488 = CAST(0 AS NUMERIC))
GROUP BY T1._Q_000_F_000RRef,
T1._Q_000_F_003RRef,
T1._Q_000_F_001RRef,
T1._Q_000_F_002RRef
GroupAggregate  (cost=5.02..5.04 rows=1 width=100) (actual time=0.125..0.127 rows=1 loops=1)
  Output: t1._q_000_f_001rref, t1._q_000_f_002rref, CASE WHEN (t1._q_000_f_003rref = ANY ('{"\\\\xb1d1beafbad9c0774db3de2a711949ce","\\\\xa782b624f6c172e34ec0db5c6d3191d8","\\\\x9dea53dea22f24fa4c099f824ba6da6e"}'::bytea[])) THEN sum(t2._fld33213) WHEN (t1._q_000_f_003rref = '\\x80ef186faedbda5740b399f2360bdc74'::bytea) THEN sum(t4._fld33309) ELSE NULL::numeric END, t1._q_000_f_000rref, t1._q_000_f_003rref
  Group Key: t1._q_000_f_000rref, t1._q_000_f_003rref, t1._q_000_f_001rref, t1._q_000_f_002rref
  Buffers: shared hit=20, local hit=1
  ->  Sort  (cost=5.02..5.02 rows=1 width=78) (actual time=0.113..0.114 rows=1 loops=1)
        Output: t1._q_000_f_001rref, t1._q_000_f_002rref, t1._q_000_f_000rref, t1._q_000_f_003rref, t2._fld33213, t4._fld33309
        Sort Key: t1._q_000_f_000rref, t1._q_000_f_003rref, t1._q_000_f_001rref, t1._q_000_f_002rref
        Sort Method: quicksort  Memory: 25kB
        Buffers: shared hit=20, local hit=1
        ->  Nested Loop Left Join  (cost=0.73..5.00 rows=1 width=78) (actual time=0.097..0.099 rows=1 loops=1)
              Output: t1._q_000_f_001rref, t1._q_000_f_002rref, t1._q_000_f_000rref, t1._q_000_f_003rref, t2._fld33213, t4._fld33309
              Buffers: shared hit=20, local hit=1
              ->  Nested Loop Left Join  (cost=0.39..3.41 rows=1 width=73) (actual time=0.074..0.075 rows=1 loops=1)
                    Output: t1._q_000_f_001rref, t1._q_000_f_002rref, t1._q_000_f_003rref, t1._q_000_f_000rref, t4._fld33309
                    Buffers: shared hit=12, local hit=1
                    ->  Seq Scan on pg_temp.tt7 t1  (cost=0.00..1.01 rows=1 width=68) (actual time=0.008..0.009 rows=1 loops=1)
                          Output: t1._q_000_f_000rref, t1._q_000_f_001rref, t1._q_000_f_002rref, t1._q_000_f_003rref, t1._q_000_f_004, t1._q_000_f_005, t1._q_000_f_006, t1._q_000_f_007
                          Buffers: local hit=1
                    ->  Nested Loop  (cost=0.39..2.39 rows=1 width=56) (actual time=0.063..0.064 rows=0 loops=1)
                          Output: t4._fld33309, t4._fld33304rref, t4._fld33305rref, t5._fld33135rref
                          Join Filter: ((t1._q_000_f_001rref = t4._fld33304rref) AND (t1._q_000_f_002rref = t4._fld33305rref))
                          Rows Removed by Join Filter: 7
                          Buffers: shared hit=12
                          ->  Index Only Scan using _document1328_4x1 on public._document1328x1 t5  (cost=0.17..1.29 rows=1 width=34) (actual time=0.030..0.030 rows=1 loops=1)
                                Output: t5._fld2488, t5._fld33135rref, t5._idrref
                                Index Cond: ((t5._fld2488 = '0'::numeric) AND (t5._fld33135rref = t1._q_000_f_000rref))
                                Heap Fetches: 0
                                Buffers: shared hit=4
                          ->  Index Scan using _document1328_vt33302_skx1 on public._document1328_vt33302x1 t4  (cost=0.22..0.93 rows=14 width=56) (actual time=0.022..0.030 rows=7 loops=1)
                                Output: t4._document1328_idrref, t4._fld2488, t4._keyfield, t4._lineno33303, t4._fld33304rref, t4._fld33305rref, t4._fld33306rref, t4._fld33307rref, t4._fld33308, t4._fld33309, t4._fld33310rref, t4._fld33311, t4._fld33312rref, t4._fld33313, t4._fld33314rref, t4._fld33315rref, t4._fld112251rref, t4._fld33316, t4._fld33317, t4._fld33318, t4._fld33319, t4._fld33320, t4._fld33321, t4._fld33322, t4._fld33323, t4._fld33325rref, t4._fld101275, t4._fld77517, t4._fld77518rref, t4._fld77519, t4._fld33324rref, t4._fld77520rref, t4._fld101276rref, t4._fld81551, t4._fld88569rref, t4._fld112252, t4._fld112253
                                Index Cond: ((t4._fld2488 = '0'::numeric) AND (t4._document1328_idrref = t5._idrref))
                                Filter: (NOT t4._fld77517)
                                Buffers: shared hit=8
              ->  Nested Loop  (cost=0.34..1.58 rows=1 width=56) (actual time=0.021..0.022 rows=1 loops=1)
                    Output: t2._fld33213, t2._fld33210rref, t2._fld33211rref, t3._fld33135rref
                    Join Filter: ((t1._q_000_f_001rref = t2._fld33210rref) AND (t1._q_000_f_002rref = t2._fld33211rref))
                    Buffers: shared hit=8
                    ->  Index Only Scan using _document1328_4x1 on public._document1328x1 t3  (cost=0.17..1.29 rows=1 width=34) (actual time=0.005..0.005 rows=1 loops=1)
                          Output: t3._fld2488, t3._fld33135rref, t3._idrref
                          Index Cond: ((t3._fld2488 = '0'::numeric) AND (t3._fld33135rref = t1._q_000_f_000rref))
                          Heap Fetches: 0
                          Buffers: shared hit=4
                    ->  Index Scan using _document1328_vt33208_skx1 on public._document1328_vt33208x1 t2  (cost=0.17..0.28 rows=1 width=56) (actual time=0.014..0.014 rows=1 loops=1)
                          Output: t2._document1328_idrref, t2._fld2488, t2._keyfield, t2._lineno33209, t2._fld33210rref, t2._fld33211rref, t2._fld33212, t2._fld33213, t2._fld33214rref, t2._fld33215_type, t2._fld33215_rtref, t2._fld33215_rrref, t2._fld33216rref, t2._fld33217rref, t2._fld33218, t2._fld33219, t2._fld33220, t2._fld33221, t2._fld33222, t2._fld33223, t2._fld33224, t2._fld33225, t2._fld33226_type, t2._fld33226_rtref, t2._fld33226_rrref, t2._fld33227_type, t2._fld33227_rtref, t2._fld33227_rrref, t2._fld33236_type, t2._fld33236_rtref, t2._fld33236_rrref, t2._fld33229, t2._fld33230rref, t2._fld33231, t2._fld33232rref, t2._fld33233_type, t2._fld33233_rtref, t2._fld33233_rrref, t2._fld33234_type, t2._fld33234_rtref, t2._fld33234_rrref, t2._fld33235_type, t2._fld33235_rtref, t2._fld33235_rrref, t2._fld33237, t2._fld33238, t2._fld33239rref, t2._fld33240, t2._fld33241rref, t2._fld33242rref, t2._fld77511, t2._fld77512, t2._fld77513, t2._fld88563rref, t2._fld88564rref, t2._fld104367, t2._fld104368, t2._fld112249, t2._fld81859
                          Index Cond: ((t2._fld2488 = '0'::numeric) AND (t2._document1328_idrref = t3._idrref))
                          Filter: (NOT t2._fld33240)
                          Buffers: shared hit=4
Settings: max_parallel_workers_per_gather = '0', effective_io_concurrency = '128', maintenance_io_concurrency = '128', random_page_cost = '1.1', from_collapse_limit = '20', join_collapse_limit = '20', max_parallel_workers = '13', hash_mem_multiplier = '8', temp_buffers = '189MB', work_mem = '378MB', effective_cache_size = '279GB', selectivity_model = '1c', enable_mergejoin = 'off', cpu_operator_cost = '0.001'
*/

F.4.9. Настройка и рекомендации #

  • Шумные среды (1С): используйте пороги для подавления мелких узлов:

    auto_dump.dump_on_bad_plan = on
    auto_dump.bad_plan_min_expected_rows = 100
    auto_dump.bad_plan_min_actual_rows   = 100
    auto_dump.bad_plan_count_threshold   = 1000
    auto_dump.bad_plan_percent_threshold = 300
    
  • Если у многих планов estimate = 0 и вы всё же хотите отлавливать их по абсолютной ошибке, отключите порог в процентах:

    auto_dump.bad_plan_percent_threshold = 0
    
  • Чтобы ограничить объем дампа во время диагностики:

    auto_dump.dump_plan = off
    auto_dump.dump_persistent_tables = off
    auto_dump.dump_all_temp_tables = off
    

F.4.10. Устранение неполадок #

  • Дампы не отображаются:

    • Проверьте, что auto_dump.enable = on, а также что auto_dump.output_directory установлен и доступен для записи.

    • Убедитесь, что shared_preload_libraries включает auto_dump, и сервер был перезапущен.

    • Проверьте, действительно ли выполнено условие триггера (подстрока / отмена / неверный план).

  • Сбой сервера при отмене или дампе плана:

    • Убедитесь, что вы запускаете сервер, собранный с патчем ProcessInterrupts_hook .

  • Слишком много дампов:

    • Увеличьте пороги и пределы (смотрите раздел конфигурации).

    • Используйте триггер по подстроке для точечного срабатывания при анализе проблемы (auto_dump.dump_on_query_string).

  • Постоянные таблицы отсутствуют в дампах:

    • Установите auto_dump.dump_persistent_tables = on.