big-trot,
В книге "PostgreSQL 9 Administration Cookbook" Simon Riggs, Hannu Krosing
есть функция pg_relation_size_nolock которая показывает как узнать физический размер который занимает таблица на диске.
CREATE OR REPLACE FUNCTION pg_relation_size_nolock(tablename regclass)
RETURNS BIGINT
LANGUAGE plpgsql
AS $$
DECLARE
classoutput RECORD;
tsid INTEGER;
rid INTEGER;
dbid INTEGER;
filepath TEXT;
filename TEXT;
datadir TEXT;
i INTEGER := 0;
tablesize BIGINT;
BEGIN
--
-- получаем директорию с данными
--
EXECUTE 'SHOW data_directory' INTO datadir;
-- получаем relfilenode и reltablespace
SELECT reltablespace as tsid,relfilenode as rid INTO classoutput
FROM pg_class
WHERE oid = tablename
AND relkind = 'r';
--
-- генерируем ошибку если не можем найти указанную таблицу
--
IF NOT FOUND THEN
RAISE EXCEPTION 'tablename % not found', tablename;
END IF;
tsid := classoutput.tsid;
rid := classoutput.rid;
--
-- получаем внутренний идентификатор объекта самй БД - oid
--
SELECT oid INTO dbid
FROM pg_database
WHERE datname = current_database();
--
-- используем внутренее представление о формировании полного имени файла
--
IF tsid = 0 THEN
filepath := datadir || '/base/' || dbid || '/' || rid;
ELSE
filepath := datadir || '/pg_tblspc/' || tsid || '/' || dbid || '/' || rid;
END IF;
--
-- получаем размер полученного файла
--
SELECT (pg_stat_file(filepath)).size INTO tablesize;
--
-- суммируем размеры всех возможных дополнительных файлов, если они есть
--
WHILE FOUND LOOP
i := i + 1;
filename := filepath || '.' || i;
--
-- pg_stat_file возвращает ERROR если не может найти файл
-- таким образом мы знаем, что больше нечего искать
--
BEGIN
SELECT tablesize + (pg_stat_file(filename)).size INTO tablesize;
EXCEPTION
WHEN OTHERS THEN EXIT;
END;
END LOOP;
RETURN tablesize;
END;
$$;
далее используете следующее
-- создаем таблицу нужной структуры и обеспечиваем существование таблицы вне транзакции копирования данных
select * into table_dest from table_source where 1=2;
-- начинаем копирование
insert into table_dest select * from table_source;
в другом соединении выполняем команду
select round(pg_relation_size_nolock('table_dest'::regclass)*100.0/pg_relation_size_nolock('table_source'::regclass),2);
теперь мы можем видеть в % как много еще осталось скопировать.
Если же разделить полученный размер в байтах (pg_relation_size_nolock('table_dest'::regclass)) на среднюю ширину строки, то можно получить приблизительный объем вставленных строк.