Postgresql:数据库不接受命令以避免数据丢失



创建/删除/更新查询时出错:

错误:数据库不接受避免环绕数据的命令数据库"mydb"中的丢失提示:停止postmaster并使用独立的后端来清空数据库。您可能还需要提交或回滚准备好的旧事务。

因此,数据库被阻塞,只能执行SELECT查询。

数据库的大小为350 GB。1个表(my_table)有大约10亿行。

system:"PostgreSQL 9.3.4 on x86_64-unknown-linux-gnu,由gcc(gcc)4.4.7 20120313(Red Hat 4.4.7-4)编译,64位"

postgresq.conf一些设置:

effective_io_concurrency = 15           # 1-1000; 0 disables prefetching
autovacuum_vacuum_cost_delay = -1
#vacuum_cost_delay = 0                  # 0-100 milliseconds
#vacuum_cost_page_hit = 1               # 0-10000 credits
#vacuum_cost_page_miss = 10             # 0-10000 credits
#vacuum_cost_page_dirty = 20            # 0-10000 credits
#vacuum_cost_limit = 200 

我不使用准备好的交易。但基本的存储过程每天要使用5000万次(这意味着自动转换,对吧?)。

当前正在执行"autovacuum:VACUUM ANALYZE public。my_table(以防止缠绕)",这几乎是该查询活动的12个小时。

据我所知,没有用吸尘器吸尘的问题是不是?

如何解决这个问题并防止将来出现这种情况?请帮忙:)

故事结束(大约一个月后)现在,我的大表被划分为数千个表。每张小桌子的吸尘速度都快得多。自动真空配置设置得更接近默认值。如果需要的话,我可以再次设置为更具攻击性,但到目前为止,具有数十亿行的数据库运行得很好。

因此,这个话题的问题不应该再次出现。

ps现在我将PostgresXL作为数据可伸缩性的下一步。

问题不是死元组,而是控制行可见性的事务id。每个事务都得到一个顺序的XID,因为它们是32位的int,所以它们最终会循环使用。

请参阅此处了解更多详细信息:http://www.postgresql.org/docs/9.3/static/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND,但简短的版本是,至少每20亿个事务需要对所有表进行VACUUM ed(手动或使用自动真空)。你不抽真空的时间越长,需要的时间就越长。

要解决当前的问题,你不需要做VACUUM ANALYZE,只需要做VACUUM——我不确定速度差有多大,但应该更快。

这是在什么样的硬件上运行的,maintenance_work_mem设置为什么?你可能想提高它(可能是暂时的)以更快地完成真空。

在未来,你基本上只需要更多地真空:要么增加自动真空频率(见此处:https://dba.stackexchange.com/questions/21068/aggressive-autovacuum-on-postgresql例如),甚至用cron安排手动真空。另请查看vacuum_freeze_min_age和相关设置。

它是什么样的数据,您正在运行什么样的事务?这是一个相当大的表,它能被分区(例如按日期)吗?

编辑

您可能还想启用log_autovacuum_min_duration(将其设置为一个小值),以查看数据库运行时autovacuum实际在做什么,以及是否存在阻止其运行的锁定问题。

回复评论

您不需要独立运行VACUUM,您现在可以运行它,除非这会对其他数据库造成太大干扰。只需要以超级用户的身份进行操作,所以系统表也会被清空。

进行转储/恢复似乎很激烈,我无法想象它会比完成VACUUM更快。

从存储过程中切换出来并没有帮助:任何修改数据的查询都会生成XID,如果显式使用事务也没关系,它们仍然是事务。

你走在了正确的道路上——让autovacuum跟上你的插入/更新是最好的解决方案(记录它的活动应该有助于了解现在出了什么问题)。

根据您的表结构判断,这可能是表分区的经典情况(http://www.postgresql.org/docs/9.3/static/ddl-partitioning.html)-我认为这都是插入,而不是更新/删除,这是对的吗?如果你总是写一个小分区,你可以更积极地抽真空(每个表可以配置自动真空),真空冷冻其他分区。

我认为您别无选择,只能停止数据库,以独立模式重新启动,然后进行真空操作。让autovac完成不会有帮助,因为一旦它完成,它将更新系统目录以反映完成情况,而更新将被拒绝,因为它无法获得所需的事务ID。至少这是我的经验。

至于将来防止它,你会定期重新启动数据库吗?如果你每24小时重新启动一次数据库,但你有一个需要30小时才能清空的表,那么这个表永远不会被成功清空,你最终会遇到麻烦。

最新更新