Мертвые кортежи - не ваша проблема.
Ваша настоящая проблема в другом месте; Я выделил это в следующем.
Последовательное сканирование в медленном запросе:
Buffers: shared hit=3015376 read=16753169 <strong>dirtied=1759802 written=1360458</strong>
Последовательное сканирование в быстром запросе:
Buffers: shared hit=15812 read=19753809
Похоже, что около двух миллионов блоков таблиц содержат кортежи, которые были недавно написаны или обновлены.
На момент написания кортежа PostgreSQL еще не знает, будет ли транзакция подтверждена или откатана, поэтому эта информация не сохраняется в кортеже. Однако он записывается в протоколе фиксации , который хранится в pg_xact
(или pg_clog
, в зависимости от вашей версии).
Теперь первый читатель, который придет и прочитает недавно написанный кортеж, должен будет просмотреть журнал фиксации, чтобы выяснить, существует ли кортеж & ldquo; существует & rdquo; или нет. Чтобы избавить будущих читателей от хлопот, он устанавливает так называемые биты подсказок в кортеже для отражения этой информации.
Это меняет и, следовательно, & ldquo; грязи & rdquo; блок, содержащий кортеж, и если у вас небольшая настройка shared_buffers
и исчерпаны доступные буферы, серверная часть даже должна будет записать блоки в хранилище, чтобы очистить их и освободить место.
Это письмо делает ваш запрос таким медленным.
Очистка таблицы устраняет проблему, потому что VACUUM
не только очищает мертвые кортежи, но и устанавливает биты подсказок для вас (это тоже читатель!).
Чтобы убедиться в этом, запустите тот же SELECT
во второй раз без очистки таблицы, и вы увидите, что с 3 миллионами мертвых кортежей это будет так же быстро, потому что теперь биты подсказок все установлены.
Это одна из причин, по которой может быть хорошей идеей запускать VACUUM
в таблице после загрузки большого количества строк, даже если нечего очищать & ndash; Вы экономите первому читателю много работы.
Идея: ли увеличение shared_buffers
улучшить ситуацию?
Но поскольку очистка таблицы решает проблему, вы также можете использовать автоочистку для более частой установки битов подсказок.
Для этого вы можете установить autovacuum_vacuum_scale_factor
в 0 и установить autovacuum_vacuum_threshold
в большую константу ( way больше 10000), чтобы никогда не было слишком много строк без битов подсказки.
Кроме того, установите autovacuum_vacuum_cost_delay
на 0, чтобы автовакуум заканчивался быстро.
Не изменять эти параметры глобально, используйте ALTER TABLE ... SET (...)
, чтобы установить их только для этой таблицы.