А расскажите, пожалуйста, как реагирует postgres на отключение клиента во время выполнения запроса? Когда клиент отправляет COMMIT: сразу со всем запросом или нет? Можно как-нибудь сделать так, чтобы клиент отправил на выполнение долгий запрос и мог отключится, а бэкенд закоммитил всё после завершения?
Отключение клиента во время долгого запроса
А расскажите, пожалуйста, как реагирует postgres на отключение клиента во время выполнения запроса?
Видит что клиент отвалился (если видит) и прерывает запрос.
Когда клиент отправляет COMMIT: сразу со всем запросом или нет?
Так как клиент написан смотря. Просто 1 SQL команда она и без Begin/commit выполняется транзакционно.
Можно как-нибудь сделать так, чтобы клиент отправил на выполнение долгий запрос и мог отключится, а бэкенд закоммитил всё после завершения?
Нет (штатными методами).
Иногда бекэнд может выполнять запрос до упора и понять что клиент отвалился уже после того как запрос выполнился. Keepalive как такогого между бекендом и клиентом нет. Сталкивались неоднократно что на серваке остаются жить бекенды без соединений со стороны клиента. Ладно бы они ресурсов не потребляли, потребляют и под 100%.
Проверить такое можно просто - запустить вставку, например боль менее толстых записей(100-1000 строк int,md5(txt) )в pg с использованием 1000 соединений и того же pgbench и после того как система встанет колом отрубить pgbench. Долгое время бекенды будут жить без клиентских подключений и потреблять при этом ресурсы системы
Бэкенд узнает о том, что у него отвалился сокет только при попытке в него записать, а писать в него он будет только после завершения выполнения запроса, чтобы отправить клиенту результаты.
Помочь может параметр statement_timeout, но значения для него лучше выбирать консервативные, иначе есть риск отстрелить просто долго выполняющийся запрос.
postgres=# create extension dblink;
CREATE EXTENSION
postgres=# create table test(id int);
CREATE TABLE
postgres=# SELECT dblink_connect('pg', 'dbname=postgres');
dblink_connect
----------------
OK
(1 row)
postgres=# select dblink_send_query('pg','insert into test select id from generate_series(1,10000000)as id '); dblink_send_query
-------------------
1
(1 row)
postgres=# \q
[postgres@thunder2 tmp]$ /home/postgres/usr/local/pgproee96/bin/psql
psql (9.6.9)
Type "help" for help.
postgres=# select count(*) from test; count
-------
0
(1 row)
postgres=# select count(*) from test;
count
----------
10000000
(1 row)
У нас сейчас пилится патчик, чтобы бэкенд pollом или select
ом изредка сокет под собой шупал.