Научимся оценивать в процентном соотношении разрастание таблиц или индексов в PostgreSQL. Для оценки будем использовать расширение pgstattuple.
Подключаем расширение pgstattuple
В начале скомпилируем расширение pgstattuple, которое поможет понять сколько в базе данных полезной информации, а сколько служебной или неактуальной. Для этого перейдем в каталог с исходниками и выполним:
postgres@s-pg13:~$ exit выход root@s-pg13:~# cd ~/pg/postgresql-13.3/contrib/pgstattuple/ root@s-pg13:~/pg/postgresql-13.3/contrib/pgstattuple# make ... root@s-pg13:~/pg/postgresql-13.3/contrib/pgstattuple# make install ... root@s-pg13:~/pg/postgresql-13.3/contrib/pgstattuple# su - postgres
Затем подключим расширение в самой базе данных с помощью команды CREATE EXTENSION:
postgres@s-pg13:~$ psql Timing is on. psql (13.3) Type "help" for help. postgres@postgres=# CREATE EXTENSION pgstattuple; CREATE EXTENSION Time: 45,688 ms
Проводим тестирование
Создадим табличку bloat и наполним её данными. После чего сделаем для этой таблицы индекс:
postgres@postgres=# CREATE TABLE bloat (id serial, s text); CREATE TABLE Time: 7,015 ms postgres@postgres=# INSERT INTO bloat(s) SELECT g.id::text FROM generate_series(1,100000) AS g(id); INSERT 0 100000 Time: 210,917 ms postgres@postgres=# CREATE INDEX ON bloat(s); CREATE INDEX Time: 331,867 ms
Теперь с помощью функции pgstattuple(‘таблица’), которая входит в расширение pgstattuple узнаем сколько в таблице полезной информации, а сколько неактуальной или служебной:
postgres@postgres=# SELECT * FROM pgstattuple('bloat') \gx
-[ RECORD 1 ]------+--------
table_len | 4423680
tuple_count | 100000
tuple_len | 3388895
tuple_percent | 76.61
dead_tuple_count | 0
dead_tuple_len | 0
dead_tuple_percent | 0
free_space | 16552
free_percent | 0.37
Time: 8,817 ms
Из вывода нам важно посмотреть на два параметра:
- tuple_percent — процент полезной информации;
- free_percent — процент свободного пространства (неактуальные строки и пустоты).
Если от 100% вычтем tuple_percent и free_percent, то получим приблизительный размер служебной информации.
Теперь посмотрим на разрастание индекса с помощью функции pgstatindex(‘индекс’):
postgres@postgres=# SELECT * FROM pgstatindex('bloat_s_idx') \gx
-[ RECORD 1 ]------+--------
version | 4
tree_level | 1
index_size | 2260992
root_block_no | 3
internal_pages | 1
leaf_pages | 274
empty_pages | 0
deleted_pages | 0
avg_leaf_density | 89.83
leaf_fragmentation | 0
Time: 1,678 ms
Из вывода обратите внимание на колонку avg_leaf_density — это заполненность страниц индекса. Если заполненность небольшая, значит в страницах есть пустоты.
Следующим шагом обновим половину строк, а затем опять посмотрим на разрастание таблицы:
postgres@postgres=# UPDATE bloat SET s = s || '!' WHERE id % 2 = 0;
UPDATE 50000
Time: 343,118 ms
postgres@postgres=# SELECT * FROM pgstattuple('bloat') \gx
-[ RECORD 1 ]------+--------
table_len | 6635520
tuple_count | 100000
tuple_len | 3438895
tuple_percent | 51.83
dead_tuple_count | 0
dead_tuple_len | 0
dead_tuple_percent | 0
free_space | 2017232
free_percent | 30.4
Time: 8,563 ms
Тут мы уже видим что tuple_percent упал до 51,83 %. То есть половина таблицы имеет неактуальные версии строк, dead_tuple_count — это количество неактуальных строк.
И еще раз посмотрим на индекс:
postgres@postgres=# SELECT * FROM pgstatindex('bloat_s_idx') \gx
-[ RECORD 1 ]------+--------
version | 4
tree_level | 2
index_size | 4513792
root_block_no | 412
internal_pages | 3
leaf_pages | 547
empty_pages | 0
deleted_pages | 0
avg_leaf_density | 45.15
leaf_fragmentation | 49.91
Time: 0,545 ms
И здесь мы видим, что avg_leaf_density упал до 45.15 %. То есть в страницах образовались пустоты. Эти пустоты постепенно будут заполнятся, а когда в таблицу придет autovacuum, то неактуальные версии строк будут удалены. Так что avtovacuum и работа сервера PostgreSQL постепенно поправят ситуацию.
Если понравилась статья, подпишись на мой канал в VK или Telegram.