Автоматическая очистка Postgresql занимает слишком много времени

У меня есть таблица db, в которой около 5-6 миллионов записей, и для очистки требуется около 20 минут. Поскольку одно поле этой таблицы обновляется очень часто, приходится иметь дело с большим количеством мертвых строк.

Для оценки, с нашей текущей пользовательской базой ежедневно может быть 2 миллиона мертвых кортежей. Итак, очистка этой таблицы требует:

  1. Чтение ввода-вывода: поскольку вся таблица отсутствует в общей памяти.
  2. Напишите IO: так как есть много записей для обновления.

Каким должен быть идеальный способ пропылесосить этот стол? Должен ли я увеличить autovacuum_cost_limit, чтобы разрешить больше операций за один запуск автоочистки? Но, как я вижу, это увеличит IOPS, что опять же может снизить производительность. В настоящее время у меня есть autovacuum_scale_factor = 0.2. Должен ли я уменьшить его? Если я уменьшу его, он будет запускаться чаще, хотя количество операций ввода-вывода уменьшится, но это приведет к большему количеству периодов времени с высокой скоростью чтения.

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

Одно из решений, о которых я подумал:

  1. Выделите сильно обновленную колонку и сделайте отдельную таблицу.
  2. Настройка параметра, чтобы он запускался чаще, чтобы уменьшить количество операций записи (как обсуждалось выше). Как справиться с дополнительным чтением ввода-вывода, так как вакуум теперь будет запускаться чаще?
  3. Объедините пункт 2 вместе с увеличением оперативной памяти, чтобы также уменьшить количество операций чтения.

В общем, какой подход используют люди, потому что я предполагаю, что у людей должна быть очень большая таблица размером 10 ГБ или более, которую необходимо очистить.


person hardik24    schedule 13.07.2020    source источник
comment
Какая у вас версия PostgreSQL?   -  person jjanes    schedule 13.07.2020
comment
@jjanes я использую postgresql 11   -  person hardik24    schedule 13.07.2020
comment
Насколько велик ваш стол? Позже вы упомянули 10 ГБ для гипотетической таблицы, это размер вашей таблицы? Делает ли это среднюю ширину кортежа около 1800 байт?   -  person jjanes    schedule 13.07.2020
comment
Нет. Моя таблица (исключая индексы) составляет около 1,5 ГБ (6 млн строк). Мне интересно, что произойдет, если я достигну такого размера через какое-то время.   -  person hardik24    schedule 13.07.2020
comment
Должен ли я отделить этот столбец, чтобы размер каждого кортежа был мал для вакуума?   -  person hardik24    schedule 13.07.2020


Ответы (2)


Есть два подхода:

  1. Уменьшите autovacuum_vacuum_cost_delay для этой таблицы, чтобы автоочистка стала быстрее. Он по-прежнему будет потреблять ввод-вывод, ЦП и ОЗУ.

  2. Установите fillfactor для таблицы на значение меньше 100 и убедитесь, что часто обновляемый столбец не индексируется. Тогда вы сможете получать ГОРЯЧИЕ обновления, которые не требуют VACUUM.

person Laurenz Albe    schedule 13.07.2020
comment
Что произойдет, если это поле будет проиндексировано? - person hardik24; 13.07.2020
comment
Вы не получите ГОРЯЧЕЕ обновление и в конечном итоге получите множество мертвых кортежей и запусков автоочистки. - person Laurenz Albe; 13.07.2020
comment
Это определенно улучшит скорость записи и уменьшит размер стены для передачи реплике чтения. Есть ли способ улучшить чтение ввода-вывода? Должен ли я отделить более обновленный столбец в новую таблицу? Чтобы при уборке читалось меньше? - person hardik24; 13.07.2020
comment
Вы можете рассмотреть возможность размещения столбца в другой таблице. Вам еще предстоит много пылесосить. - person Laurenz Albe; 13.07.2020
comment
Я понимаю, но это решит много проблем. Просто для общего сведения: Postgres — очень широко используемая база данных, и у людей должны быть миллиарды строк в одной таблице, которую необходимо очищать, иногда чаще (скажем, раз в день). Итак, будет ли он потреблять весь ввод-вывод машины за то время, пока он будет работать? - person hardik24; 13.07.2020
comment
Он будет потреблять столько операций ввода-вывода, сколько может один поток, который замедляется из-за случайных переходов в спящий режим. - person Laurenz Albe; 14.07.2020

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

Почему вас волнует, что это займет 20 минут? Это вызывает что-то плохое? С такой скоростью вы могли бы чистить этот стол 72 раза в день, что, кажется, гораздо чаще, чем на самом деле нужно. В v12 значение по умолчанию для autovacuum_vacuum_cost_delay было уменьшено в 10 раз, до 2 мс. Это изменение по умолчанию было вызвано не изменениями в коде в версии 12, а скорее осознанием того, что старое значение по умолчанию в большинстве случаев просто устарело для современного оборудования. У меня не возникло бы проблем с внесением этого изменения в конфигурацию v11; но я не думаю, что это также решит вашу главную проблему.

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

В настоящее время у меня autovacuum_scale_factor = 0,2. Должен ли я уменьшить его? Если я уменьшу его, он будет запускаться чаще, хотя количество операций ввода-вывода уменьшится, но это приведет к большему количеству периодов времени с высокой скоростью чтения.

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

person jjanes    schedule 13.07.2020
comment
Это не создает никаких проблем как таковых, но то, о чем я беспокоюсь из-за интенсивной записи ввода-вывода, заключается в том, что он будет передавать файлы wal для реплики чтения, которая затем из-за высокого ввода-вывода будет иметь более высокую репликацию. Если говорить о Read IO, я просто хочу убедиться, что в будущем это не повлияет на производительность запросов. - person hardik24; 13.07.2020
comment
Ваш комментарий о том, что увеличение пробега на самом деле приведет к увеличению числа записей, теперь имеет для меня смысл. Это определенно может уменьшиться для одного запуска, но в целом это только увеличит его. В этом случае, я думаю, ответ Лоренца (с использованием fillfactor) может помочь. - person hardik24; 13.07.2020
comment
Просто информация: что делают люди, когда у них есть очень большая таблица с миллиардами строк, которую нужно обновлять, а очистку нужно запускать чаще? Там может потребоваться много времени, чтобы на самом деле пропылесосить стол? Одним из возможных вариантов может быть сегментирование, чтобы разделить таблицу/базу данных на несколько машин, каждая из которых имеет собственную пропускную способность ввода-вывода? - person hardik24; 13.07.2020
comment
@ hardik24 Я думаю, что очень редко бывает, когда в таблице миллиарды строк, и ›30% из них переворачиваются каждый день. Если у вас действительно есть такая ситуация, вы должны иметь возможность бросить гораздо больше операций ввода-вывода на автоочистку или полностью отключить регулирование ввода-вывода. v13 также представит параллельную очистку (только для таблиц с несколькими индексами). Разделение (или просто разделение) также может помочь, но я думаю, что это обычно делается по другим причинам, а не только для очистки. - person jjanes; 16.07.2020