Большое количество живых / мертвых кортежей в postgresql / вакуум не работает

есть таблица , которая имеет 200 строк . Но количество живых кортежей, показывающих, что есть больше, чем это (около 60K) .

select count(*) from subscriber_offset_manager;
 count 
-------
   200
(1 row)


 SELECT schemaname,relname,n_live_tup,n_dead_tup FROM pg_stat_user_tables  where relname='subscriber_offset_manager' ORDER BY n_dead_tup
;
 schemaname |          relname          | n_live_tup | n_dead_tup 
------------+---------------------------+------------+------------
 public     | subscriber_offset_manager |      61453 |          5
(1 row)

но, как видно из pg_stat_activity и pg_locks , мы не можем отслеживать любое открытое соединение .

SELECT query, state,locktype,mode
FROM pg_locks
JOIN pg_stat_activity
  USING (pid)
WHERE relation::regclass = 'subscriber_offset_manager'::regclass
  ;
 query | state | locktype | mode 
-------+-------+----------+------
(0 rows)

Я также попробовал полный вакуум на этой таблице, ниже приведены результаты:

  • все время, когда строки не удаляются
  • несколько раз, все живые становятся мертвыми кортежи кортежей .

здесь выход .

vacuum FULL VERBOSE ANALYZE subscriber_offset_manager;
INFO:  vacuuming "public.subscriber_offset_manager"
INFO:  "subscriber_offset_manager": found 0 removable, 67920 nonremovable row versions in 714 pages
DETAIL:  67720 dead row versions cannot be removed yet.
CPU 0.01s/0.06u sec elapsed 0.13 sec.
INFO:  analyzing "public.subscriber_offset_manager"
INFO:  "subscriber_offset_manager": scanned 710 of 710 pages, containing 200 live rows and 67720 dead rows; 200 rows in sample, 200 estimated total rows
VACUUM

 SELECT schemaname,relname,n_live_tup,n_dead_tup FROM pg_stat_user_tables  where relname='subscriber_offset_manager' ORDER BY n_dead_tup
;
 schemaname |          relname          | n_live_tup | n_dead_tup 
------------+---------------------------+------------+------------
 public     | subscriber_offset_manager |        200 |      67749

и через 10 секунд

SELECT schemaname,relname,n_live_tup,n_dead_tup FROM pg_stat_user_tables  where relname='subscriber_offset_manager' ORDER BY n_dead_tup
;
 schemaname |          relname          | n_live_tup | n_dead_tup 
------------+---------------------------+------------+------------
 public     | subscriber_offset_manager |      68325 |        132

как наш запрос приложения к этой таблице .

  • наше приложение обычно выбирает некоторые строки и на основе некоторого бизнес-расчета обновляет строку .

    запрос SELECT -- выберите на основе некоторого id

    выберите * из subscriber_offset_manager, где shard_id=1;

    обновление запрос -- обновите другой столбец для этого выбранного идентификатора осколка

  • около 20 потоков делают это параллельно, и один поток работает только на одной строке .

  • приложение написано на java, и мы используем hibernate для выполнения операций с БД .
  • версия Postgresql-9.3.24

еще одно интересное наблюдение : - когда я останавливаю свое java-приложение, а затем делаю полный вакуум, он работает нормально (количество строк и живые кортежи становятся равными). Таким образом, что-то не так, если мы выбираем и постоянно обновляем из приложения java . –

/Выпуска

эти живые кортежи несколько раз переходят в мертвые кортежи и через несколько раз снова оживают .

из-за вышеуказанного поведения выберите из таблицы время и увеличение нагрузки на сервер, так как есть много живых/мертвых ..

3 ответов


Я знаю три вещи, которые держат VACUUM от выполнения своей работы:

  • длительные транзакции.

  • подготовленные транзакции, которые не были зафиксированы.

  • устаревшие слоты репликации.

посмотреть мой блог для сведения.


Я получил вопрос ☺ .

для понимания вопроса рассмотрим следующий поток:

резьбы 1 -

  • открывает сеанс гибернации
  • сделайте несколько запросов на Таблица-A
  • выберите subscriber_offset_manager
  • обновление subscriber_offset_manager .
  • закрывает сессию .

много потоков типа поток-1 параллельно .

поток 2 -

  • эти типы потоков выполняются параллельно .
  • открывает сеанс гибернации
  • сделайте несколько запросов select на Таблица-A
  • не закрывает сеанс .(утечка сеанса .)

Временное Разрешение - если я закрою все эти соединения, сделанные Thread-2 с помощью pg_cancel_backend, то вакуумирование начинает работать .

также мы воссоздали проблему много раз и попробовали это решение, и оно сработало .

Итак, есть следующие сомнения, которые до сих пор не ответили .

  1. почему postgres не показывает никаких данных, связанных с таблицей"subscriber_offset_manager" .
  2. эта проблема не воссоздается, когда вместо запуска поток-2, если мы запустим select on Таблица-A, используя psql .
  3. почему postgres работает так с jdbc .

еще несколько сногсшибательных наблюдений:

  1. событие, если мы запускаем запросы на"subscriber_offset_manager " в другой сессии, то также вопрос приходит;
  2. мы нашли много экземпляров здесь, где поток 2 работает над какой-то третьей таблицей "Таблица-C " и выпуск идет
  3. все эти транзакции типа od находятся в pg_stat_activity-это "idle_in_transaction ."

@Erwin Brandstetter и @Laurenz Albe, если вы знаете, что есть ошибка, связанная с postgres / jdbc .


в конце концов, могут быть блокировки, ваш запрос может ввести в заблуждение:

SELECT query, state,locktype,mode
FROM pg_locks
JOIN pg_stat_activity USING (pid)
WHERE relation = 'subscriber_offset_manager'::regclass

pg_locks.pid может быть NULL, тогда соединение устранит строки. руководство по Postgres 9.3:

идентификатор процесса серверного процесса, удерживающего или ожидающего эту блокировку,или null, если блокировка удерживается подготовленной транзакцией

жирным выделено мной. (Все то же самое на стр. 10.)

сделать что-нибудь для простой вопрос?

SELECT * FROM pg_locks
WHERE relation = 'subscriber_offset_manager'::regclass;

это может объяснить, почему VACUUM жалуется:

DETAIL:  67720 dead row versions cannot be removed yet.

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

моей первой мыслью было бы длительные транзакции, где еще простой SELECT (приобретение смирен ACCESS SHARE блокировка) может блок VACUUM от выполнения своей работы. 20 нитей параллельно могут цепляться и блокироваться VACUUM безгранично. Держите свои транзакции (и их блокировки) как можно короче. И убедитесь, что ваши запросы оптимизированы и не блокируют больше строк, чем необходимо.

еще одно замечание: изоляции транзакции уровень SERIALIZABLE или REPEATABLE READ сделать это намного сложнее VACUUM очистить. По умолчанию READ COMMITTED режим менее ограничительный, но VACUUM все еще может быть заблокирован, как описано.

по теме: