Рост столов TOAST вышел из-под контроля - FULLVAC ничего не делает

9

Недавно у меня был сервер PostgreSQL 8.2.11, обновленный до 8.4, чтобы использовать возможности автоочистки и соответствовать 30 другим серверам PGSQL. Это было сделано отдельной ИТ-группой, которая администрирует аппаратное обеспечение, поэтому у нас нет большого выбора для других обновлений (некоторое время мы не увидим 9+). Сервер существует в очень закрытой среде (изолированная сеть, ограниченные привилегии root) и работает на RHEL5.5 (i686). После обновления база данных постоянно росла до 5-6 ГБ в день. Обычно база данных в целом составляет ~ 20 ГБ; в настоящее время это ~ 89 ГБ. У нас есть пара других серверов, которые работают с эквивалентными базами данных и фактически синхронизируют записи друг с другом через стороннее приложение (у меня нет доступа к внутренней работе). Другие базы данных ~ 20 ГБ, как и должно быть.

При выполнении следующего SQL-кода совершенно очевидно, что существует проблема с конкретной таблицей, а точнее с ее таблицей TOAST.

SELECT nspname || '.' || relname AS "relation",
    pg_size_pretty(pg_relation_size(C.oid)) AS "size"
  FROM pg_class C
  LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
  WHERE nspname NOT IN ('pg_catalog', 'information_schema')
  ORDER BY pg_relation_size(C.oid) DESC
  LIMIT 20;

Который производит:

              отношение | размер  
------------------------------------ + ---------  
  pg_toast.pg_toast_16874 | 89 ГБ  
  twos00.warmstates | 1095 МБ  
  ...  
(20 рядов)

Эта таблица TOAST предназначена для таблицы, называемой «временной серией», в которой хранятся большие записи данных большого размера. A SUM(LENGTH(blob)/1024./1024.)из всех записей во временных сериях дает ~ 16 ГБ для этого столбца. Не должно быть никаких причин, по которым таблица TOAST этой таблицы должна быть такой же большой, как и она.

Я выполнил VACUUM FULL VERBOSE ANALYZE timeseries, и вакуум работает до конца без ошибок.

ИНФОРМАЦИЯ: очистка "pg_toast.pg_toast_16874"
ИНФОРМАЦИЯ: "pg_toast_16874": найдено 22483 сменных, 10475318 неустранимых версий строк на 10448587 страницах
ПОДРОБНОЕ ОПИСАНИЕ : 0 версий мертвых строк еще не могут быть удалены.
Неизменяемые версии строк имеют длину от 37 до 2036 байт.
Были 20121422 неиспользованных указателей предметов.
Общий объем свободного места (включая версии съемных строк) составляет 0 байт. 4944885 страниц являются или станут пустыми, включая 0 в конце таблицы. 4944885 страниц, содержащих 0 свободных байтов, являются потенциальными местами перемещения.
Процессор 75,31 с / 29,59u с истек 877,79 с.
ИНФОРМАЦИЯ: индекс «pg_toast_16874_index» теперь содержит 10475318 версий строк на 179931 страницах
. ПОДРОБНЕЕ: 23884 версии строк индекса были удалены.
101623 страницы индекса были удалены, 101623 в настоящее время могут использоваться повторно.
Процессор 1,35 с / 2,46u сек. Прошло 21,07 с.

Переиндексирована таблица , которая освобожденная некоторое пространство (~ 1 Гб). Я не могу кластеризовать таблицу, так как на диске недостаточно места для процесса, и я жду полной перестройки таблицы, поскольку мне хотелось бы выяснить, почему она намного больше, чем у эквивалентных баз данных, которые у нас есть.

Запустил запрос из вики PostgreSQL здесь - «Показать раздувание базы данных» , и вот что я получаю:

current_database | имя схемы | имя таблицы | тблоат | wastedbytes | Инаме | иблоат | wastedibytes  
----------------- + ------------ + ------------------- ------------- + -------- + ------------- + ------------- -------------------- + -------- + --------------  
ptrdb04 | Несколько00 | временные ряды | 1.0 | 0 | idx_timeseries_synchlevel | 0.0 | 0  
ptrdb04 | Несколько00 | временные ряды | 1.0 | 0 | idx_timeseries_localavail | 0.0 | 0  
ptrdb04 | Несколько00 | временные ряды | 1.0 | 0 | idx_timeseries_expirytime | 0.0 | 0  
ptrdb04 | Несколько00 | временные ряды | 1.0 | 0 | idx_timeseries_expiry_null | 0.0 | 0  
ptrdb04 | Несколько00 | временные ряды | 1.0 | 0 | uniq_localintid | 0.0 | 0  
ptrdb04 | Несколько00 | временные ряды | 1.0 | 0 | pk_timeseries | 0,1 | 0  
ptrdb04 | Несколько00 | idx_timeseries_expiry_null | 0,6 | 0 | ? | 0.0 | 0

Похоже, что база данных вообще не считает это пространство «пустым», но я просто не вижу, откуда берется все дисковое пространство!

Я подозреваю, что этот сервер баз данных решает использовать в 4-5 раз больше дискового пространства для сохранения тех же записей, которые извлекаются с других серверов данных. У меня такой вопрос: есть ли способ проверить размер физического диска в строке? Я хотел бы сравнить размер одной строки в этой базе данных с другой "здоровой" базой данных.

Спасибо за любую помощь, вы можете предоставить!

ОБНОВЛЕНИЕ 1

Я закончил тем, что восстановил таблицу из сброшенной схемы из-за ее размера (не мог оставить это в покое в течение другого дня). После синхронизации данных через программный процесс синхронизации таблица TOAST составляла ~ 35 ГБ; однако из этого столбца BLOB-объектов я мог получить только ~ 9 ГБ, что должно быть самым длинным с точки зрения значений. Не уверен, откуда поступают остальные 26 ГБ. КЛАСТЕР, ВАКУУМ ПОЛНЫЙ, И ПОВТОРЕННЫЙ безрезультатно. В postgresql.conf файлы между локальными и удаленными серверами баз данных в точности то же самое. Есть ли какая-либо причина, по которой эта база данных пытается хранить каждую запись с большим пространством на диске?

ОБНОВЛЕНИЕ 2 - Исправлено

В конце концов я решил полностью перестроить базу данных с нуля, вплоть до переустановки пакетов PostgreSQL84 в системе. Путь к базе данных был повторно инициализирован, а табличные пространства очищены. Сторонний процесс синхронизации программного обеспечения заново заполнил таблицы, и окончательный размер оказался ~ 12 ГБ ! К сожалению, это никоим образом не помогает решить, какой именно источник проблемы был здесь. Я собираюсь просмотреть его в течение дня или двух и посмотреть, есть ли какие-либо существенные различия в том, как обновленная база данных обрабатывает таблицу TOAST, и выложить эти результаты здесь.

Размер отношения


ptrdb04=> SELECT nspname || '.' || relname AS "relation",
ptrdb04->     pg_size_pretty(pg_relation_size(C.oid)) AS "size"
ptrdb04->   FROM pg_class C
ptrdb04->   LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
ptrdb04->   WHERE nspname NOT IN ('pg_catalog', 'information_schema')
ptrdb04->   ORDER BY pg_relation_size(C.oid) DESC
ptrdb04->   LIMIT 2;

        отношение          |   размер   
 ------------------------- + --------- 
 pg_toast . pg_toast_17269 | 18 ГБ 
 fews00 . теплые состояния        | 1224 МБ
 ( 2 строки )  

VACUUM VERBOSE ANALYZE timeseries;

ИНФОРМАЦИЯ: «временные ряды»: найдено 12699 съемных, 681961 несъемных версий строк в 58130 из 68382 страниц
ДЕТАЛИ: 0 версий мертвых строк еще не могут быть удалены.
Было 105847 неиспользованных указателей предметов.
0 страниц полностью пусты.
Процессор 0,83 с / 2,08u с прошел 33,36 с.
ИНФОРМАЦИЯ: пылесос "pg_toast.pg_toast_17269"
ИНФОРМАЦИЯ: отсканированный индекс "pg_toast_17269_index" для удаления 2055849 версий строк
ДЕТАЛИ: ЦП 0,37 с / 2,92 с прошло 13,29 с.
ИНФОРМАЦИЯ: "pg_toast_17269": удалены версии строк 2055849 на 518543 страницах
ДЕТАЛИ: ЦП 8,60 с / 3,21 с прошло 358,42 с.
ИНФОРМАЦИЯ: индекс "pg_toast_17269_index" теперь содержит 7346902 версий строк на 36786 страницах
ПОДРОБНОЕ: 2055849 версии строки индекса были удалены.
10410 страниц индекса были удалены, 5124 в настоящее время могут использоваться повторно.
CPU 0.00s / 0.00u сек. Прошло 0,01 сек.
ИНФОРМАЦИЯ: "pg_toast_17269": найдено 1286128 съемных, 2993389 несъемных версий строк в 1257871 из 2328079 страниц
ДЕТАЛИ: 0 версий мертвых строк еще не могут быть удалены.
Было 18847 неиспользованных указателей предметов.
0 страниц полностью пусты.
Процессор 26,56 с / 13,04 с прошел 714,97 с.
ИНФОРМАЦИЯ: анализируя "lesss00.timeseries"
ИНФОРМАЦИЯ: «timeseries»: отсканировано 30000 из 68382 страниц, содержащих 360192 живых строк и 0 мертвых строк; 30000 строк в выборке, 821022 расчетных строк

Единственная заметная разница после восстановления (кроме использования диска)

ИНФОРМАЦИЯ: "pg_toast_17269": найдено 1286128 съемных, 2993389 несъемных версий строк
как @CraigRinger упоминается в комментарии. Количество несменяемых строк намного меньше, чем раньше.

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

BrM13
источник
Почему вы не обновились до 9.2? У него еще больше улучшений в области вакцины, чем в 8,4 (а 8,4 в следующем году будет EOL)
a_horse_with_no_name
Я обновил пост. Обновление не было сделано нашим магазином и не обязательно по нашему запросу. К сожалению, у нас нет этой возможности для обновления до 9+.
BrM13
ХОРОШО. Я просто хотел убедиться, что вы не упускаете из виду очевидное;)
a_horse_with_no_name
Смотрите также stackoverflow.com/questions/23120072/...
rogerdpack

Ответы:

9

Эта:

INFO: "pg_toast_16874": found 22483 removable, 10475318 nonremovable row versions in 10448587 pages 22483 removable, 10475318 nonremovable row versions in 10448587 pages

предполагает, что основная проблема заключается в том, что что-то еще может «видеть» эти строки, поэтому их нельзя удалить.

Кандидаты на это:

  • Потерянные готовые сделки. Проверить pg_catalog.pg_prepared_xacts; оно должно быть пустым. Также беги SHOW max_prepared_transactions; это должно сообщить ноль.

  • Длительные сеансы с открытой незанятой транзакцией. В PostgreSQL 8.4 и выше это должно быть проблемой только для SERIALIZABLEтранзакций. Проверьте pg_catalog.pg_stat_activityдля <IDLE> in transactionсессий.

Скорее всего, у вас есть клиент, которому не удается зафиксировать или откатить транзакции в течение длительных периодов простоя.

Если это не так, то следующее, что я проверю, - это сумма octet_sizeвсех столбцов таблицы интересов. Сравните это со pg_relation_sizeстолом и его TOASTприставным столом. Если есть большая разница, то занимаемое пространство, вероятно, больше не видны строки, и у вас, вероятно, есть проблемы с раздуванием таблицы. Если они очень похожи, вы можете начать сужать, где используется пространство, суммируя размеры октетов на столбец, получая верхние значения 'n' и т. Д.

Крейг Рингер
источник
1) pg_prepared_xacts и max_prepared_transactions действительно вернулись пустыми. 2) Определенно есть несколько транзакций IDLE, из SELECT * FROM pg_stat_activity WHERE current_query LIKE '<IDLE>%';которых возвращается около 30-40 результатов; однако это кажется довольно нормальным. Я проверил несколько «здоровых» серверов, и они были одинаковыми.
BrM13
3) Вот что я сделал. Перебирая столбцы временных рядов, вытягивая octet_length (столбец). Умножил каждое значение на количество строк и суммировал их. Для временных рядов я получил ~ 430 МБ (близко к 493 МБ из pg_relation_size) и 438 МБ для таблицы TOAST (используя столбцы chunk_id, chunk_seq, chunk_data). Оценки выглядят корректно, и таблица TOAST ОТКЛЮЧЕНА от размера_отношения примерно на 2 порядка (сегодня 60 ГБ). Похоже, у меня есть вздутие, но не традиционный вид (неиспользованный раздув). В противном случае FULLVAC должен позаботиться о проблеме.
BrM13
@Brad Свободные сеансы в порядке, проблема заключается только в бездействующих сеансах с открытыми транзакциями , т. Е. <IDLE> in transactionТолько в том случае, если они (а) простаивают некоторое время и (б) используют SERIALIZABLEизоляцию, или вы используете 8.3 или старшая.
Крейг Рингер,
@Brad Интересно, что только TOASTтаблица кажется раздутой, хотя. Кстати, если вы много используете VACUUM FULLна серверах до 9.0, вам нужно, так REINDEXкак VACUUM FULLв этих версиях это может привести к значительному увеличению индекса. Теперь я задаюсь вопросом, не поставил ли кто-нибудь абсурд FILLFACTORна тостовом столе, хотя это не должно позволить вам преодолеть 10-кратное потребление пространства.
Крейг Рингер,
Спасибо за разъяснение IDLE. Я подумал, что ты это имел ввиду, но это приятно знать наверняка. Что касается FILLFACTOR, таблица использует значение по умолчанию. К сведению - в соответствии с документацией 8.4 CREATE TABLE по умолчанию установлено значение 100, и вы не можете установить FILLFACTOR для таблицы TOAST.
BrM13
0

Я не понимаю, почему это раздутый. Но я немного искал и, возможно, эта ссылка имеет некоторое представление: http://postgresql.1045698.n5.nabble.com/A-154-GB-table-swelled-to-527-GB-on-the-Slony-slave -Как-компактно-это-td5543034.html ... Это не ваша точная ситуация, но, возможно, это достаточно близко, чтобы помочь вам добраться до сути фантомного раздувания.

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

Вот мое предложение: создайте табличное пространство на другом диске с большим количеством дополнительного пространства, а затем назначьте свою таблицу проблем этому табличному пространству. PostgreSQL скопирует таблицу в новое табличное пространство (возможно, в процессе ее блокирует таблица, поэтому вам потребуется окно обслуживания). Затем VACFULL таблицы (очищает большую часть старого пространства, используемого таблицей в табличном пространстве по умолчанию). Тогда КЛАСТЕР стол и он должен сжаться. Затем поместите его обратно в табличное пространство по умолчанию и снова запустите VACFULL (чтобы очистить неиспользуемое пространство в новом табличном пространстве).

efesar
источник
Я фактически закончил перестройку таблицы (сброс схемы и восстановление из нее) и извлечение данных непосредственно из одной из удаленных баз данных. После того, как процесс был завершен, база данных все еще оставалась 35 ГБ, и только 9 ГБ приходилось на «широкий» столбец больших двоичных объектов. CLUSTERed, VACUUM FULLed, REINDEXed, и я все еще сижу на куче загадочных дисков.
BrM13,
Ссылка мертва :(
Хайд