Задачи эксперимента
Оценить степень влияния регулярного выполнения vacuum/analyze на производительность СУБД.
Оценить степень влияния распухания таблицы на производительность СУБД.
Реализация эксперимента
Виртуальная машина
CPU = 1
vendor_id : GenuineIntel
cpu family : 6
model : 85
model name : Intel Xeon Processor (Skylake, IBRS, no TSX)
RAM
Mem: 718Mi
Редакция/версия СУБД
Postgres Pro (enterprise certified) 15.8.1 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 11.4.1 20230605 (Red Soft 11.4.0-1), 64-bit
Конфигурационные параметры СУБД
shared_preload_libraries = 'pg_stat_statements'
Остальные параметры: по умолчанию
Инициализация тестовых таблиц
Создать и заполнить таблицы данными
recreate.sql
DROP TABLE IF EXISTS table_parent ;
CREATE TABLE table_parent
(
id SERIAL ,
name text ,
curr_value numeric
);
DROP TABLE IF EXISTS table_child1 ;
CREATE TABLE table_child1
(
id SERIAL ,
parent_key integer ,
name text ,
curr_value numeric
);
DROP TABLE IF EXISTS table_child2 ;
CREATE TABLE table_child2
(
id integer ,
parent_key integer ,
name text ,
curr_value numeric
);
INSERT INTO table_parent ( name , curr_value )
SELECT i::text , i::numeric
FROM generate_series(1, 1000000) AS t(i) ;
INSERT INTO table_child1 ( parent_key , name , curr_value )
SELECT i::numeric , i::text , i::numeric
FROM generate_series(300, 900000) AS t(i) ;
INSERT INTO table_child2 ( id , parent_key , name , curr_value )
SELECT i::numeric , i::numeric , i::text , i::numeric
FROM generate_series(20000, 800000) AS t(i) ;
Индексировать и собрать статистику по таблицам
index_analyze.sql
CREATE INDEX table_parent_idx ON table_parent ( id );
CREATE INDEX table_child1_idx ON table_child1 ( parent_key );
CREATE INDEX table_child2_idx ON table_child2 ( parent_key );
ANALYZE table_parent ;
ANALYZE table_child1 ;
ANALYZE table_child2 ;
Итерация теста
generator3.sql
CREATE OR REPLACE FUNCTION generator3() RETURNS integer AS $$
DECLARE
result_rec record ;
BEGIN
SELECT child1.name , child2.name
INTO result_rec
FROM table_parent parent
join table_child1 child1 ON ( parent.id = child1.parent_key )
join table_child2 child2 ON ( parent.id = child2.parent_key )
WHERE
( parent.id > 500000 AND parent.id < 500100 ) and ( parent.id % 2 = 0 );
INSERT INTO table_child2 ( id , parent_key , name , curr_value )
SELECT i::numeric , i::numeric , i::text , i::numeric
FROM generate_series(900000, 910000) AS t(i) ;
UPDATE table_child2
SET name = name || 'test'
WHERE id between 900000 AND 910000 ;
DELETE FROM table_child2
WHERE id between 900000 AND 910000 ;
return 0 ;
END
$$ LANGUAGE plpgsql;
Тест
generator3.4.sh
#!/bin/sh
#generator3.4.sh
#version.3.4
script=$(readlink -f $0)
current_path=`dirname $script`
LOG_FILE=$current_path'/generator.log'
echo 'TIMESTAMP : '$(date "+%d-%m-%Y %H:%M:%S") ' : OK : START '
echo 'TIMESTAMP : '$(date "+%d-%m-%Y %H:%M:%S") ' : OK : START '> $LOG_FILE
/opt/pgpro/ent-15/bin/psql -d test_db -c "select pg_stat_reset()" >> $LOG_FILE
if [ $? -ne 0 ]
then
#####################################################################
#ОШИБКА СУБД
echo 'ERROR : PostgreSQL ERROR : pg_stat_reset TERMINATED WITH ERROR '
echo 'ERROR : PostgreSQL ERROR : pg_stat_statements_reset TERMINATED WITH ERROR ' >> $LOG_FILE
exit 1000
#####################################################################
fi
/opt/pgpro/ent-15/bin/psql -d test_db -c "select pg_stat_statements_reset()" >> $LOG_FILE
if [ $? -ne 0 ]
then
#####################################################################
#ОШИБКА СУБД
echo 'ERROR : PostgreSQL ERROR : pg_stat_statements_reset TERMINATED WITH ERROR '
echo 'ERROR : PostgreSQL ERROR : pg_stat_statements_reset TERMINATED WITH ERROR ' >> $LOG_FILE
exit 1000
#####################################################################
fi
for ((i=1; i <= 1000; i++))
do
echo 'PASS = '$i
echo 'PASS = '$i>> $LOG_FILE
/opt/pgpro/ent-15/bin/psql -d test_db -c "select generator3()"
if [ $? -ne 0 ]
then
#####################################################################
#ОШИБКА СУБД
echo 'ERROR : PostgreSQL ERROR : generator TERMINATED WITH ERROR '
echo 'ERROR : PostgreSQL ERROR : generator TERMINATED WITH ERROR ' >> $LOG_FILE
exit 1000
#####################################################################
fi
done
echo 'TIMESTAMP : '$(date "+%d-%m-%Y %H:%M:%S") ' : OK : FINISHED '
echo 'TIMESTAMP : '$(date "+%d-%m-%Y %H:%M:%S") ' : OK : FINISHED '>> $LOG_FILE
exit 0
Оцениваемые результаты
Общее время выполнения (total_exec_time представления pg_stat_statements)
Количество запросов (calls представления pg_stat_statements)
Количество результирующих строк (rows представления pg_stat_statements)
Общее число прочитанных разделяемых блоков (shared_blks_read представления pg_stat_statements)
Общее число «загрязнённых» разделяемых блоков (shared_blk_dirtied представления pg_stat_statements)
Общее число записанных разделяемых блоков (shared_blk_written представления pg_stat_statements)
Количество транзакций (xact_commit представления pg_stat_database)
Метрика производительности СУБД (CPI)
Результаты эксперимента
Эталонный тест: vacuum + analyze после каждой итерации

Тест без выполнения vacuum + analyze после каждой итерации

Сравнение результатов с «Эталонный тест: vacuum + analyze после каждой итерации»
Время выполнения теста — незначительно уменьшилось
Объем обработанных разделяемых блоков — значительно увеличился
Производительность — существенно уменьшилась
Фрагментация 11%

Сравнение результатов с «Тест без выполнения vacuum + analyze после каждой итерации»
Время выполнения теста — существенно увеличилось
Объем обработанных разделяемых блоков — существенно увеличился
Производительность — существенно уменьшилась
Фрагментация 100%

Сравнение результатов с «Тест без выполнения vacuum + analyze после каждой итерации»
Время выполнения теста — существенно увеличилось
Объем обработанных разделяемых блоков — существенно увеличился
Производительность — существенно уменьшилась
Итоги
Выполнение vacuum+analyze после массовых изменений данных существенно увеличивает производительность СУБД, хотя общее время выполнения и несколько возрастает.
Даже относительно небольшая фрагментация оказывает существенное влияние на производительность СУБД.
Дальнейшее увеличение фрагментации не оказывает заметного влияния на производительность СУБД.
Мониторить и оптимизировать надо не фрагментацию БД в целом, а фрагментацию наиболее часто используемых таблиц.