PostgresQL автоматизация вакуума полный для раздутых таблиц
у нас есть продукт, использующий сервер баз данных PostgreSQL, который развернут на нескольких сотнях клиентов. Некоторые из них собрались десятки гигабайт данных за эти годы. Поэтому в следующей версии мы введем автоматизированные процедуры очистки, которые будут постепенно архивировать и удалить старые записи во время ночных пакетных заданий.
если я правильно понял, то автовакуума пнет внутри и проанализирует и реорганизует кортежи, поэтому производительность будет такой же, как тогда, когда существовало меньше записей.
фактическое дисковое пространство не будет освобождено, если я правильно понимаю, так как это происходит только с ВАКУУМ ПОЛНЫЙ, и это не вызвано автовакуума.
поэтому я думал об автоматическом процессе, который бы это сделал.
я нашел представление раздувания, которое используется nagios check_postgres в http://wiki.postgresql.org/wiki/Show_database_bloat.
этот вид хорош? Правильно ли я понимаю, что если tbloat is > 2, он может использовать полный вакуум? И если ibloat слишком высоко, он может использовать РЕИНДЕКС?
любые комментарии к следующему заданию для запуска как ежедневное пакетное задание?
-
vacuumdb -Z mydatabase
#вакуум анализировать-только select tablename from bloatview order by tbloat desc limit 1
vacuumdb -f -t tablename mydatabase
select tablename, iname from bloatview order by ibloat desc limit 1
reindexdb -t tablename -i iname mydatabase
конечно, мне все еще нужно обернуть его в хороший скрипт perl в crontab (мы используем ubuntu 12), или у postgresql есть какой-то планировщик, с которым я мог бы это сделать?
или это перебор и есть гораздо более простая процедура?
2 ответов
вам, вероятно, не нужно. Хорошо сделать это один раз-после первого задания архивирования, чтобы вы получили свое дисковое пространство, но после этого ваша ежедневная работа архивирования и autovacuum предотвратят вздутие мертвых кортежей.
и вместо vacuum full
часто лучше работать cluster table_name using index_name; analyze table_name
. Это изменит порядок строк в соответствии с индексом. Таким образом, связанные строки таблицы могут быть сохранены физически близко на диске, что может ограничить поиск диска (важно на классических дисках, в значительной степени не имеет значения на SSD) и несколько чтений для ваших типичных запросов.
и помните, что как vacuum full
и cluster
сделает ваши таблицы непригодными для использования во время их запуска.
хорошо, я прошел через это.
я упростил / переработал представление, чтобы разделить его на следующие два:
CREATE OR REPLACE VIEW
bloat_datawidth AS
SELECT
ns.nspname AS schemaname,
tbl.oid AS relid,
tbl.relname,
CASE
WHEN every(avg_width IS NOT NULL)
THEN SUM((1-null_frac)*avg_width) + MAX(null_frac) * 24
ELSE NULL
END AS datawidth
FROM
pg_attribute att
JOIN
pg_class tbl
ON
att.attrelid = tbl.oid
JOIN
pg_namespace ns
ON
ns.oid = tbl.relnamespace
LEFT JOIN
pg_stats s
ON
s.schemaname=ns.nspname
AND s.tablename = tbl.relname
AND s.inherited=false
AND s.attname=att.attname
WHERE
att.attnum > 0
AND tbl.relkind='r'
GROUP BY
1,2,3;
и
CREATE OR REPLACE VIEW
bloat_tables AS
SELECT
bdw.schemaname,
bdw.relname,
bdw.datawidth,
cc.reltuples::bigint,
cc.relpages::bigint,
ceil(cc.reltuples*bdw.datawidth/current_setting('block_size')::NUMERIC)::bigint AS expectedpages,
100 - (cc.reltuples*100*bdw.datawidth)/(current_setting('block_size')::NUMERIC*cc.relpages) AS bloatpct
FROM
bloat_datawidth bdw
JOIN
pg_class cc
ON
cc.oid = bdw.relid
AND cc.relpages > 1
AND bdw.datawidth IS NOT NULL;
и задание cron:
#!/bin/bash
MIN_BLOAT=65
MIN_WASTED_PAGES=100
LOG_FILE=/var/log/postgresql/bloat.log
DATABASE=unity-stationmaster
SCHEMA=public
if [[ "$(id -un)" != "postgres" ]]
then
echo "You need to be user postgres to run this script."
exit 1
fi
TABLENAME=`psql $DATABASE -t -A -c "select relname from bloat_tables where bloatpct > $MIN_BLOAT and relpages-expectedpages > $MIN_WASTED_PAGES and schemaname ='$SCHEMA' order by wastedpages desc limit 1"`
if [[ -z "$TABLENAME" ]]
then
echo "No bloated tables." >> $LOG_FILE
exit 0
fi
vacuumdb -v -f -t $TABLENAME $DATABASE >> $LOG_FILE