Автоочистка

Создадим таблицу с 1000 строками:

=> CREATE DATABASE mvcc_autovacuum;
CREATE DATABASE
=> \c mvcc_autovacuum
You are now connected to database "mvcc_autovacuum" as user "postgres".
=> CREATE TABLE tvac(id serial, n numeric);
CREATE TABLE
=> INSERT INTO tvac(n) SELECT 1 FROM generate_series(1,1000);
INSERT 0 1000

Выставим настройки автоочистки.

Небольшое время ожидания, чтобы сразу видеть результат:

=> ALTER SYSTEM SET autovacuum_naptime = 1;
ALTER SYSTEM

Один процент строк:

=> ALTER SYSTEM SET autovacuum_vacuum_scale_factor = 0.01;
ALTER SYSTEM

Нулевой порог:

=> ALTER SYSTEM SET autovacuum_vacuum_threshold = 0;
ALTER SYSTEM

Выставим настройки автоанализа.

Два процента строк:

=> ALTER SYSTEM SET autovacuum_analyze_scale_factor = 0.02;
ALTER SYSTEM

Нулевой порог:

=> ALTER SYSTEM SET autovacuum_analyze_threshold = 0;
ALTER SYSTEM

Перечитаем настройки:

=> SELECT pg_reload_conf();
 pg_reload_conf 
----------------
 t
(1 row)

И подождем немного, чтобы сработал автоанализ.


Создадим представление, показывающее, нуждается ли наша таблица в очистке.

=> CREATE VIEW vacuum_v AS
WITH params AS (
  SELECT (SELECT setting::integer
          FROM   pg_settings
          WHERE  name = 'autovacuum_vacuum_threshold') AS vacuum_threshold,
         (SELECT setting::float
          FROM   pg_settings
          WHERE  name = 'autovacuum_vacuum_scale_factor') AS vacuum_scale_factor
)
SELECT st.relname,
       st.n_dead_tup dead_tup,
       (p.vacuum_threshold + p.vacuum_scale_factor*c.reltuples)::integer max_dead_tup,
       st.n_dead_tup > (p.vacuum_threshold + p.vacuum_scale_factor*c.reltuples)::integer need_vacuum,
       st.last_autovacuum
FROM   pg_stat_all_tables st,
       pg_class c,
       params p
WHERE  c.oid = st.relid
AND    c.relname = 'tvac';
CREATE VIEW

Проверим.

=> SELECT * FROM vacuum_v;
 relname | dead_tup | max_dead_tup | need_vacuum | last_autovacuum 
---------+----------+--------------+-------------+-----------------
 tvac    |        0 |           10 | f           | 
(1 row)

Таблица не требует очистки (0 ненужных версий) и ни разу не очищалась.


Можно создать аналогичное представление и для анализа:

=> CREATE VIEW analyze_v AS
WITH params AS (
  SELECT (SELECT setting::integer
          FROM   pg_settings
          WHERE  name = 'autovacuum_analyze_threshold') as analyze_threshold,
         (SELECT setting::float
          FROM   pg_settings
          WHERE  name = 'autovacuum_analyze_scale_factor') as analyze_scale_factor
)
SELECT st.relname,
       st.n_mod_since_analyze mod_tup,
       (p.analyze_threshold + p.analyze_scale_factor*c.reltuples)::integer max_mod_tup,
       st.n_mod_since_analyze > (p.analyze_threshold + p.analyze_scale_factor*c.reltuples)::integer need_analyze,
       st.last_autoanalyze
FROM   pg_stat_all_tables st,
       pg_class c,
       params p
WHERE  c.oid = st.relid
AND    c.relname = 'tvac';
CREATE VIEW

Проверим.

=> SELECT * FROM analyze_v;
 relname | mod_tup | max_mod_tup | need_analyze |       last_autoanalyze        
---------+---------+-------------+--------------+-------------------------------
 tvac    |       0 |          20 | f            | 2019-08-12 17:15:26.825879+03
(1 row)

Таблица не требует анализа; автоанализ уже был выполнен.


Отключим автоочистку на уровне таблицы и изменим 11 строк (больше 1 %):

=> ALTER TABLE tvac SET (autovacuum_enabled = off);
ALTER TABLE
=> UPDATE tvac SET n = n + 1 WHERE id <= 11;
UPDATE 11

=> SELECT * FROM vacuum_v;
 relname | dead_tup | max_dead_tup | need_vacuum | last_autovacuum 
---------+----------+--------------+-------------+-----------------
 tvac    |       11 |           10 | t           | 
(1 row)

=> SELECT * FROM analyze_v;
 relname | mod_tup | max_mod_tup | need_analyze |       last_autoanalyze        
---------+---------+-------------+--------------+-------------------------------
 tvac    |      11 |          20 | f            | 2019-08-12 17:15:26.825879+03
(1 row)

Как видно, таблице требуется автоочистка.


Включим автоочистку для таблицы и подождем несколько секунд...

=> ALTER TABLE tvac SET (autovacuum_enabled = on);
ALTER TABLE

=> SELECT * FROM vacuum_v;
 relname | dead_tup | max_dead_tup | need_vacuum |        last_autovacuum        
---------+----------+--------------+-------------+-------------------------------
 tvac    |        0 |           10 | f           | 2019-08-12 17:15:32.258085+03
(1 row)

=> SELECT * FROM analyze_v;
 relname | mod_tup | max_mod_tup | need_analyze |       last_autoanalyze        
---------+---------+-------------+--------------+-------------------------------
 tvac    |      11 |          20 | f            | 2019-08-12 17:15:26.825879+03
(1 row)

Автоочистка пришла и обработала таблицу. Число ненужных версий снова равно нулю. При этом автоанализ не выполнялся.


Изменим еще 11 строк:

=> ALTER TABLE tvac SET (autovacuum_enabled = off);
ALTER TABLE
=> UPDATE tvac SET n = n + 1 WHERE id <= 11;
UPDATE 11

=> SELECT * FROM vacuum_v;
 relname | dead_tup | max_dead_tup | need_vacuum |        last_autovacuum        
---------+----------+--------------+-------------+-------------------------------
 tvac    |       11 |           10 | t           | 2019-08-12 17:15:32.258085+03
(1 row)

=> SELECT * FROM analyze_v;
 relname | mod_tup | max_mod_tup | need_analyze |       last_autoanalyze        
---------+---------+-------------+--------------+-------------------------------
 tvac    |      22 |          20 | t            | 2019-08-12 17:15:26.825879+03
(1 row)

Теперь должна отработать и автоочистка, и автоанализ.


Проверим это.

=> ALTER TABLE tvac SET (autovacuum_enabled = on);
ALTER TABLE

Несколько секунд ожидания...

=> SELECT * FROM vacuum_v;
 relname | dead_tup | max_dead_tup | need_vacuum |        last_autovacuum        
---------+----------+--------------+-------------+-------------------------------
 tvac    |        0 |           10 | f           | 2019-08-12 17:15:38.606581+03
(1 row)

=> SELECT * FROM analyze_v;
 relname | mod_tup | max_mod_tup | need_analyze |       last_autoanalyze        
---------+---------+-------------+--------------+-------------------------------
 tvac    |       0 |          20 | f            | 2019-08-12 17:15:38.607967+03
(1 row)

Все правильно, отработали оба процесса.


Показанные представления можно использовать для мониторинга очереди таблиц, ожидающих очистку и анализ, убрав условие на имя таблицы. Для полноты картины в них требуется учесть параметры хранения на уровне отдельных таблиц.

=> ALTER TABLE tvac SET (autovacuum_vacuum_scale_factor = 0.01);
ALTER TABLE
=> SELECT unnest(reloptions) FROM pg_class WHERE relname = 'tvac';
               unnest                
-------------------------------------
 autovacuum_enabled=on
 autovacuum_vacuum_scale_factor=0.01
(2 rows)

Конец демонстрации.