Postgres Professional corporate blog
PostgreSQL
SQL
Comments 10
+1
Егор, спасибо за статью и отдельное спасибо за темп 1 статья в неделю. Такой темп непросто выдерживать, поэтому вдвойне благодарен. Традиционные вопросы.

Процесс autovacuum launcher составляет список баз данных, в которых есть какая-либо активность. Активность определяется по статистике, а чтобы она собиралась, должен быть установлен параметр track_counts. Никогда не выключайте autovacuum и track_counts, иначе автоочистка не будет работать.


Получается, есть еще какой-то фоновый сборщик статистики? Потому что автовакуум сам по себе собирает статистику.
Вероятно не получится так, что на основе своей же статистики он решает когда запускать сбор статистики.
+1

Спасибо, Владимир.


Получается, есть еще какой-то фоновый сборщик статистики?

Да. Поленился я начать с самого начала, поэтому обошел это вниманием…
Есть такой процесс — stats collector. Он накапливает статистику, которую постоянно получает от всех процессов, агрегирует ее и показывает в представлениях pg_stats_*. Это не та статистика, что использует планировщик и которая собирается командой ANAYZE. Подробно все это рассматривается в курсе DBA1, тема Мониторинг.

+1
Число мертвых версий постоянно собирается коллектором статистики


Анализ таблиц, который осуществляет AUTOVACUUM и коллектор статистики — это разные процессы?
+1
С автоанализом дело обстоит примерно так же. Считается, что анализа требуют ту таблицы, у которых число измененных (с момента прошлого анализа) версий строк превышает пороговое значение


А где хранится информация о том, когда именно была изменена строка?
* Запоминается дата последнего анализа
* Как именно выбрираются строки, которые изменились после? Вероятно, запоминается xmax (или горизонт событий), а не сама дата. И мониторится
разница (дельта) между горизонтом событий и последней транзакцией, которая относится к таблице. Верно?
+1
А где хранится информация о том, когда именно была изменена строка?

А такая информация и не хранится. Нет, ну по xmax можно что-то погадать, но это все не нужно.


Просто каждая транзакция в конце работы отчитывается коллектору статистики: вставила, мол, столько-то строк в такой-то таблице, да столько-то удалила, да еще столько-то изменила. А коллектор эти цифры агрегирует и складывает (см. pg_stat_all_tables).


Поэтому мы там имеем, в числе прочего, примерное общее число измененных строк (поле n_mod_since_analyze). А когда приходит анализ, он это поле обнуляет.


Как именно выбрираются строки, которые изменились после?

Никак. Их постфактум не вычислить. Да и не нужно.

+1
Очистка не блокирует другие процессы, поскольку работает постранично


Но она работает с буфферным кешем? То есть закрепляет страницы буфферного кеша + ставит физическую блокировку, чтобы
работать со страницей эксклюзивно. То есть получается, что блокировка все таки есть, если я все правильно понял.
+1

Все верно, блокирует. Но по одной страничке за раз и ненадолго. И этим не особо отличается от любого другого процесса, который что-то меняет в таблице.


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

+1
Запустившись, рабочий процесс подключается к указанной ему базе данных и начинает с того, что строит список:
всех таблиц, материализованных представлений и toast-таблиц, требующих очистки,


И снова вопрос про TOAST, немного не в тему статьи
* Пусть в таблице есть 2 поля — JSONB и TEXT.
* Пусть есть строки, в которых содержатся достаточно крупные значения в этих полях, чтобы работал TOAST
* берем одну из строк
* меняем один символ в JSONB, например в поле number_of_posts было значение 1, а стало — 2.
* Создается ли новая версия TOAST только для JSONB? То есть TOAST это таблица, где данные хранятся в виде ключ-значение?
И каждой строке основной таблицы соответствует 2 строки TOAST таблицы (на каждое из полей)?
+1
Создается ли новая версия TOAST только для JSONB?

Да.


То есть TOAST это таблица, где данные хранятся в виде ключ-значение?

Ммм?


И каждой строке основной таблицы соответствует 2 строки TOAST таблицы (на каждое из полей)?

Не обязательно. В toast-таблице будет минимум одна строка на каждый "длинный" атрибут, который не сжался и попал в тостер.


Вообще, по задумке, эти статьи должны дать не просто какие-то факты, но и показать, как эти факты можно проверить. Для этого я и привожу кучу примеров, где, что и как посмотреть. Вот возьмем и проверим.


=# CREATE TABLE ttt(a text, b text);

Пусть два текстовых поля будут для простоты, JSONB ничем не отличается. Чтобы не воевать со сжатием, поставим стратегию external:


=# ALTER TABLE ttt ALTER COLUMN a SET STORAGE EXTERNAL;
=# ALTER TABLE ttt ALTER COLUMN b SET STORAGE EXTERNAL;

Вставляем что-нибудь длинное. 3000 байт будут порезаны на два кусочка.


=# INSERT INTO ttt VALUES (repeat('a',3000), repeat('b',3000));

Находим toast-таблицу:


=# SELECT relnamespace::regnamespace, relname
FROM pg_class WHERE oid = (
  SELECT reltoastrelid FROM pg_class WHERE relname = 'ttt'
);

 relnamespace |    relname     
--------------+----------------
 pg_toast     | pg_toast_49334
(1 row)

Вот что мы там видим (сами данные не показываю):


=# SELECT chunk_id, chunk_seq FROM pg_toast.pg_toast_49334;

 chunk_id | chunk_seq 
----------+-----------
    49340 |         0
    49340 |         1
    49341 |         0
    49341 |         1
(4 rows)

Тут у нас два фрагмента (chunk_id = 49340 и 49341), в каждом — два кусочка (chunk_seq).
Теперь обновим одно поле:


=# UPDATE ttt SET a = a || 'a';
=# SELECT chunk_id, chunk_seq FROM pg_toast.pg_toast_49334;

 chunk_id | chunk_seq 
----------+-----------
    49341 |         0
    49341 |         1
    49342 |         0
    49342 |         1
(4 rows)

Фрагмент 49341 (который, очевидно, соответствует полю b) остался, а вместо 49340 (поле a) имеем 49342.

Only those users with full accounts are able to leave comments. , please.