5.2. Оптимизация DML
При оценке производительности операторов DML важно понимать, как они обрабатываются в Shardman.
Прежде всего, выполнение оператора INSERT
существенно отличается от выполнения UPDATE
и DELETE
. Поведение INSERT
для сегментированных таблиц контролируется параметром стороннего сервера batch_size
, который можно установить в разделе FDWOptions
файла конфигурации Shardman. Если batch_size
больше 0, INSERT
в одном операторе для нескольких значений, которые попадают в одну и ту же стороннюю секцию, приводит к тому, что значения группируются вместе в порции указанного размера. Удалённые операторы INSERT
подготавливаются с необходимым количеством параметров и затем выполняются с заданными значениями. Если количество значений не совпадает с количеством подготовленных аргументов, снова подготавливается изменённый оператор с необходимым количеством параметров. Оптимизация массовой вставки может завершиться ошибкой, если транзакция вставляет записи одну за другой или записи, направляемые в разные сторонние таблицы, смешиваются в одном операторе INSERT
. Порция формируется для одной операции стороннего изменения. Она отправляется на удалённый сервер при заполнении порции или при завершении операции изменения. Операция изменения завершается, когда кортежи начинают перенаправляться в другую секцию сегментированной таблицы. Таким образом, для массовой загрузки рекомендуется вставка нескольких значений в одной команде INSERT
или использование команды COPY
(поскольку она оптимизируется аналогичным образом). Большие значения batch_size
позволяют выдавать меньше операторов INSERT
на удалённой стороне и, таким образом, значительно снижают стоимость связи. Однако при формировании параметров для подготовленных операторов INSERT
все вставленные значения должны быть скопированы в память, выделенную libpq. Это может привести к неограниченному использованию памяти на стороне координатора запросов при загрузке нескольких больших объектов text
или bytea
.
Операторы UPDATE
и DELETE
могут выполняться в прямом или непрямом режиме. Прямой режим используется, когда оператор может быть напрямую отправлен на сторонний сервер. В этом режиме для изменения таблицы на удалённом сервере создаётся новый оператор на основе исходного узла плана ModifyTable
. Использование прямого изменения не всегда возможно. В частности, оно невозможно когда некоторые условия должны оцениваться локально. В этом случае используется гораздо менее эффективное непрямое изменение. Непрямое изменение включает в себя несколько операторов. Первый — SELECT FOR UPDATE
для блокировки строк на удалённой части. Второй — фактический UPDATE
или DELETE
, который готовится один раз, а затем выполняется с разными параметрами для каждой строки результата оператора SELECT FOR UPDATE
после применения к результаты локальных фильтров. Очевидно, что прямые модификации намного эффективнее.
Можно легко определить, в прямом или непрямом режиме будет выполняться оператор DML, посмотрев на план запроса. Типичный пример непрямого изменения:
EXPLAIN VERBOSE DELETE FROM pgbench_history WHERE bid = 20 AND mtime > '2023-03-14 10:00:00'::timestamptz; QUERY PLAN -------------------------------------------------------------------------------------------------------------- Delete on public.pgbench_history (cost=100.00..142.66 rows=0 width=0) Foreign Delete on public.pgbench_history_17_fdw pgbench_history_1 Remote SQL: DELETE FROM public.pgbench_history_17 WHERE ctid = $1 -> Foreign Scan on public.pgbench_history_17_fdw pgbench_history_1 (cost=100.00..142.66 rows=4 width=10) Output: pgbench_history_1.tableoid, pgbench_history_1.ctid Filter: (pgbench_history_1.mtime > '2023-03-14 10:00:00+03'::timestamp with time zone) Remote SQL: SELECT mtime, ctid FROM public.pgbench_history_17 WHERE ((bid = 20)) FOR UPDATE
При выборе другого типа строковой константы это было бы прямым изменением.
EXPLAIN VERBOSE DELETE FROM pgbench_history WHERE bid = 20 AND mtime > '2023-03-14 10:00:00'::timestamp; explain verbose delete from pgbench_history where bid = 20 and mtime > '2023-03-14 10:00:00'::timestamp; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------- Delete on public.pgbench_history (cost=100.00..146.97 rows=0 width=0) Foreign Delete on public.pgbench_history_17_fdw pgbench_history_1 -> Foreign Delete on public.pgbench_history_17_fdw pgbench_history_1 (cost=100.00..146.97 rows=4 width=10) Remote SQL: DELETE FROM public.pgbench_history_17 WHERE ((mtime > '2023-03-14 10:00:00'::timestamp without time zone)) AND ((bid = 20))
Видно, что в режиме прямого изменения на удалённом сервере выполняется только один оператор.
5.2.1. Оптимизация DML для глобальных таблиц
Настраиваемый параметр конфигурации shardman.gt_batch_size задаёт размер промежуточного буфера до отправки данных на удалённый сервер.
Операция INSERT
использует бинарный протокол и формирует порции данных размером shardman.gt_batch_size
. Высокие значения размера буфера позволяют выдавать меньше запросов по сети на удалённой стороне и, таким образом, значительно снижают стоимость связи. Однако это может привести к неограниченному использованию памяти на стороне координатора запросов. Поэтому важно найти золотую середину между стоимостью связи и размером используемой памяти.
Для операции UPDATE
на координаторе формируется запрос для каждого столбца и каждой строки и отправляется на удалённые узлы.
Для операции DELETE
на координаторе формируется запрос для порции данных с размером shardman.gt_batch_size
и рассылается на удалённые узлы.