获取PostgreSQL数据库表的最后修改日期

我试图通过检查其文件修改日期来修改我的表,如 this answer中所述.但结果并不总是正确的.更新表后几分钟内文件修改日期会更新.这是正确的行为吗? Postgresql是否将表修改存储在某个缓存中,然后将其刷新到硬盘驱动器?

那么,我如何得到一个表的正确的最后修改日期(让我们假设自动真空修改也可以)?

我在Linux Centos 6.2 x64下使用Postgresql 9.2.

表的上次修改时间没有可靠的,有效的记录.由于很多原因,使用relfilenode是错误的:

>写入最初记录到写头日志(WAL),然后懒惰地记录到堆(表文件).一旦记录在WAL中,Pg不会急于将其写入堆中,甚至可能在下一个系统检查点之前写入;
>较大的桌子有多个叉子,你必须检查所有的叉子并选择最新的时间戳;
>由于提示位设置,简单的SELECT可以为基础表生成写入活动;
> autovaccum和其他不改变用户可见数据的维护仍然会修改关系文件;
>一些操作,如真空疫苗,将取代relfilenode.如果您试图在没有采取适当锁定的情况下同时查看它,那么它可能不是您所期望的.

一些选择

如果您不需要可靠性,则可以使用pg_stat_database和pg_stat_all_tables中的信息.这些可以为您提供上次统计信息重置的时间,以及自上次统计信息重置后的活动统计信息.它没有告诉你最近的活动是什么时候,只是自上次统计数据重置以来,并且没有关于重置统计数据之前发生的事情的信息.所以它有限,但已经存在了.

可靠地执行此操作的一个选项是使用触发器更新包含每个表的最后修改间的表.请注意,这样做会序列化对表的所有写入,从而破坏并发性.它还会为每笔交易增加一些开销.我不推荐它.

稍微不那么糟糕的选择是使用LISTEN和NOTIFY.让外部守护程序进程连接到Postgresql和LISTEN以获取事件.使用ON INSERT或UPDATE或DELETE触发器在表更改时发送NOTIFY,表oid作为通知有效负载.这些在事务提交时发送.您的守护程序可以累积更改通知,并懒惰地将它们写回数据库中的表.如果系统崩溃,您将丢失最近修改的记录,但是没关系,如果您在崩溃后启动,则只需将所有表视为刚刚修改过.

为了避免最严重的并发问题,您可以使用之前的插入或更新来记录更改时间戳,或者对每个语句执行触发器使用tablename删除或截断,通用化以将关系oid作为参数.这会将(relation_oid,timestamp)对插入更改日志记录表.然后,您在单独的连接上有一个帮助程序进程,或者由您的应用程序定期调用,聚合该表以获取最新信息,将其合并到最近更改的摘要表中,并截断日志表.与listen / notify方法相比,这方面的唯一优势是它不会丢失崩溃信息 – 但它的效率也更低.

另一种方法可能是编写一个C扩展函数,它使用(例如)ProcessUtility_hook,ExecutorRun_hook等来捕获表更改并懒惰地更新统计信息.我没有看到这将是多么实际;看看源代码中的各种_hook选项.

最好的方法是修补统计信息代码以记录此信息,并向Postgresql提交补丁以包含在核心中.不要只从编写代码开始;一旦你想到它就有了明确的方法来提高你的想法(即从阅读代码开始,不要只是发帖询问“我怎么……”).将最后更新的时间添加到pg_stat _…可能会很不错,但您必须说服社区值得开销或提供一种方法来使其可选地被跟踪 – 并且您必须将代码写入保持统计数据并提交补丁,因为只有想要此功能的人才会打扰它.

我该怎么做

如果我不得不这样做,并且没有时间编写补丁来正确地执行此操作,我可能会使用上面概述的listen / notify方法.

Postgresql 9.5提交时间戳的更新

更新:Postgresql 9.5有commit timestamps.如果你在postgresql.conf中启用了它们(过去也这样做了),你可以检查具有最大xmin的行的提交时间戳,以接近最后修改的时间.它只是一个近似值,因为如果删除了最近的行,则不会计算它们.

此外,提交时间戳记录仅保留有限的时间.因此,如果你想知道什么时候修改了很多未被修改的表,那么答案实际上就是“dunno,前一段时间”.

相关文章

项目需要,有个数据需要导入,拿到手一开始以为是mysql,结果...
本文小编为大家详细介绍“怎么查看PostgreSQL数据库中所有表...
错误现象问题原因这是在远程连接时pg_hba.conf文件没有配置正...
因本地资源有限,在公共测试环境搭建了PGsql环境,从数据库本...
wamp 环境 这个提示就是说你的版本低于10了。 先打印ph...
psycopg2.OperationalError: SSL SYSCALL error: EOF detect...