【问题标题】:PostgresQL Automating VACUUM FULL for bloated tablesPostgresQL 自动化 VACUUM FULL 用于臃肿的表
【发布时间】:2012-12-18 11:30:03
【问题描述】:

我们有一个使用 PostgreSQL 数据库服务器的产品,它部署在几百个客户端上。多年来,他们中的一些人已经收集了 数十 GB 的数据。因此,在下一个版本中,我们将引入自动清理程序,该程序将在夜间批处理作业中逐步归档和DELETE旧记录。

如果我理解正确,autovacuum 会启动并分析和重组元组,因此性能会像存在较少记录时一样。

如果我理解正确的话,实际的磁盘空间不会被释放,因为这只发生在 VACUUM FULL 的情况下,并且不是由 autovacuum 触发的。 p>

所以我正在考虑一个可以做到这一点的自动化流程。

我在http://wiki.postgresql.org/wiki/Show_database_bloat 找到了 nagios check_postgres 使用的膨胀视图。

这种观点有什么好处吗?我是否正确理解如果 tbloat > 2,它可以使用 VACUUM FULL?如果 ibloat 太高,是否可以使用 REINDEX?

以下作业中是否有任何 cmets 作为每日批处理作业运行?

  • vacuumdb -Z mydatabase #vacuum 仅分析
  • 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 是否有某种调度程序我可以使用它?

或者这完全是矫枉过正,有没有更简单的程序?

【问题讨论】:

  • vacuumdb -Z 可能没有必要,autovacuum 似乎在保持分析最新方面做得很好。

标签: postgresql postgresql-9.1 nagios


【解决方案1】:

你可能不需要它。最好这样做一次——在第一次归档工作之后,这样您就可以收回磁盘空间,但之后您的日常归档工作和自动清空将防止死元组膨胀。

除了vacuum full,运行cluster table_name using index_name; analyze table_name 通常更好。这将根据索引重新排序行。通过这种方式,相关的表行可以物理地保存在磁盘上,这可以限制磁盘查找(在经典磁盘驱动器上很重要,在 SSD 上基本上不相关)和典型查询的读取次数。

请记住,vacuum fullcluster 都会使您的表在运行时无法使用。

【讨论】:

  • 感谢您的提示。我们介绍的清理过程将安排在晚上运行几个小时,但在完成之前在某些客户端需要几个晚上。我同意最好等到清理完全完成,然后在计划的停机时间内只执行一次真空或集群。只有我们需要安排大约 200 次安装,这就是为什么我们需要一些自动化。感谢您对 CLUSTER 的提示。
  • 从 Postgresql 9.0 及更高版本对 VACUUM FULL 的优化使其成为正确的方法。 (见:wiki.postgresql.org/wiki/VACUUM_FULL#CLUSTER
【解决方案2】:

好的,我已经完成了。

我简化/重新设计了视图,将其拆分为以下两个:

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

【讨论】:

    猜你喜欢
    • 2015-03-17
    • 2011-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多