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))

Видно, что в режиме прямого изменения на удалённом сервере выполняется только один оператор.