我们有一个使用PostgreSQL数据库服务器的产品,该服务器部署在几百个客户端上。多年来,他们中的一些人已经收集了数十亿字节的数据。因此,在下一个版本中,我们将引入自动清理程序,这些程序将在夜间批处理作业中逐步归档和删除旧记录。
如果我理解正确, autovacuum 将启动并分析和重新组织元组,因此性能将与存在较少记录的情况相同。
如果我理解正确的话,实际的磁盘空间将不会被释放,因为只有在 VACUUM FULL 时才会发生,并且不会由 autovacuum 触发。
所以我在想一个可以做到这一点的自动化过程。
我在http://wiki.postgresql.org/wiki/Show_database_bloat找到了nagios check_postgres使用的膨胀视图。
这种观点有什么用吗?我是否理解如果 tbloat 是> 2,它可以使用VACUUM FULL吗?如果 ibloat 太高,它可以使用REINDEX吗?
对以下作业的任何评论作为每日批处理作业运行?
vacuumdb -Z mydatabase
#vacuum with analyze-only 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
当然,我仍然需要将它包装在crontab中的一个漂亮的perl脚本中(我们使用的是ubuntu 12),或者postgresql是否有某种调度程序我可以用它来做?
或者这总是过度杀伤,是否有一个更简单的程序?
答案 0 :(得分:4)
你可能不需要它。这样做很好 - 在首次归档作业之后,您将获得磁盘空间,但之后您的每日归档作业和autovacuum将防止死元组膨胀。
而不是vacuum full
,通常最好运行cluster table_name using index_name; analyze table_name
。这将根据索引对行重新排序。通过这种方式,相关的表行可以物理地保存在磁盘上,这可以限制磁盘搜索(在传统磁盘驱动器上很重要,在SSD上很大程度上不相关)以及针对典型查询的大量读取。
请记住,vacuum full
和cluster
都会使您的桌子在运行时无法使用。
答案 1 :(得分:3)
好的,我一路走来。
我简化/重写了视图,将其拆分为以下两个:
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