Как стать автором
Обновить

Комментарии 10

Егор, спасибо за статью и отдельное спасибо за темп 1 статья в неделю. Такой темп непросто выдерживать, поэтому вдвойне благодарен. Традиционные вопросы.

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


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

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


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

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

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


Анализ таблиц, который осуществляет AUTOVACUUM и коллектор статистики — это разные процессы?

Да, совершенно разные. См. выше.

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


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

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


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


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


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

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

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


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

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


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

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


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

Зарегистрируйтесь на Хабре, чтобы оставить комментарий