prior to 9.6 fetch_size can't be set for server nor foreign table, yet we can mock up this option using dblinks for bulk operation. In the case below I speeded up ~1GB table bulk select from postgres_fdw from hour and half to two minutes by mocking up fetch_size change from 100 to 100K.
Thanks to @jjanes, I started looking into fetch_size
available from 9.6. Alas I can't go for upgrade, so I had to implement a workaround. Watching pg_stat_activity
on remote I noticed FETCH 100 FROM c1
from local server, so I thought fetch_size = 100 is probably hardcoded in prior versions. So I ran a little wrap-up to fetch data with dblink fetched by 100 rows:
truncate table bin.t1;
begin;
do
$$
declare
_r record;
begin
perform dblink_connect('past');
perform dblink_exec('BEGIN;');
perform dblink_open('cr', 'select * from rel');
for _r in 0..130*1000 loop /* I know the number of rows is apxm 130*1000*100*/
raise info '%',concat(lpad(_r::text,4,'0'),': ',clock_timestamp());
insert into bin.t1
SELECT * FROM dblink_fetch('cr', 100)
AS (a integer, b character varying(200), c double precision)
;
end loop;
perform dblink_close('cr');
perform dblink_exec('END;');
perform dblink_disconnect();
end;
$$
;
end;
DO
Time: 4235292.205 ms
db=# end;
COMMIT
Time: 89.988 ms
db=# select count(1) from bin.t1;
count
----------
12309947
(1 row)
So it took 4235 seconds... Next I increased fetch_size in my wrap-up from 100 to 100*1000:
truncate table bin.t2;
begin;
do
$$
declare
_r record;
begin
perform dblink_connect('past');
perform dblink_exec('BEGIN;');
perform dblink_open('cr', 'select * from rel');
for _r in 0..130 loop
raise info '%',concat(lpad(_r::text,4,'0'),': ',clock_timestamp());
insert into bin.t2
SELECT * FROM dblink_fetch('cr', 100*1000)
AS (a integer, b character varying(200), c double precision)
;
end loop;
perform dblink_close('cr');
perform dblink_exec('END;');
perform dblink_disconnect();
end;
$$
;
end;
DO
Time: 89606.764 ms
db=# end;
COMMIT
Time: 0.153 ms
db=# select count(1) from bin.t2;
-[ RECORD 1 ]---
count | 12309947
So I saw **FETCH 100000 FROM cr**
as expected in pg_stat_activity
and execution time changed from 4235 seconds to 90 seconds - which is 40 something times!
Last to mention that insert select from postgres_fdw
takes more or less same time as dblink wrap up with fetch 100:
db=# insert into bin.t3 select * from remote.rel;
INSERT 0 12296752
Time: 5321428.694 ms
\copy
even faster then scpfetch_size
comes with 9.6?..