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

han*_*ank 47 postgresql

我试图通过检查其文件修改日期来了解我的表何时被修改,如本答案所述。但结果并不总是正确的。更新我的表后,文件修改日期会在几分钟内更新。这是正确的行为吗?PostgreSQL 是否将表修改存储在某些缓存中,然后将其刷新到硬盘驱动器?

那么,如何获得表格的正确上次修改日期(假设自动真空修改也可以)?

我在 Linux Centos 6.2 x64 下使用 PostgreSQL 9.2。

Cra*_*ger 39

表的最后修改时间没有可靠、权威的记录。由于很多原因,使用 relfilenode 是错误的:

  • 写入最初记录到写头日志 (WAL),然后懒惰地记录到堆(表文件)。一旦记录在 WAL 中,Pg 不会急于将其写入堆中,甚至可能直到下一个系统检查点才会写入;

  • 较大的表有多个分叉,您必须检查所有分叉并选择最新的时间戳;

  • SELECT由于提示位设置,一个简单的可以生成对基础表的写入活动;

  • autovaccum 和其他不改变用户可见数据的维护仍然修改关系文件;

  • 某些操作,例如vaccum full,将替换 relfilenode。如果您试图同时查看它而不采取适当的锁定,它可能不是您所期望的。

几个选项

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

可靠地执行此操作的一种选择是使用触发器来更新包含每个表的最后修改时间的表。请注意,这样做会序列化对表的所有写入,从而破坏并发性。它还会为每个事务增加相当多的开销。我不推荐它。

一个稍微不那么糟糕的替代方法是使用LISTENand NOTIFY。有一个外部守护进程连接到 PostgreSQL 和LISTEN事件。使用ON INSERT OR UPDATE OR DELETE触发器NOTIFY在表更改时发送s,以表 oid 作为通知负载。这些在事务提交时发送。您的守护进程可以累积更改通知并懒洋洋地将它们写回数据库中的表。如果系统崩溃,您将丢失最近修改的记录,但没关系,如果您在崩溃后启动,您只需将所有表都视为刚刚修改。

为了避免最严重的并发问题,您可以改为使用before insert or update or delete or truncate on tablename for each statement execute触发器记录更改时间戳,概括为将关系 oid 作为参数。这会将一(relation_oid, timestamp)对插入到更改日志记录表中。然后,您在单独的连接上有一个辅助进程,或由您的应用程序定期调用,聚合该表以获取最新信息,将其合并到最近更改的汇总表中,并截断日志表。与监听/通知方法相比,这种方法的唯一优势是它不会丢失有关崩溃的信息——但它的效率也更低。

另一种方法可能是写一个C扩展功能使用(例如)ProcessUtility_hookExecutorRun_hook等以捕获表更改和懒惰地更新统计信息。我还没有想过这会有多实用;查看源代码中的各种 _hook 选项。

最好的方法是修补统计代码以记录此信息并向 PostgreSQL 提交修补程序以包含在核心中。不要从编写代码开始;一旦你对 -hackers 进行了充分的思考,就可以提出你的想法,并有一个明确定义的方法来做到这一点(即从阅读代码开始,不要只是发帖询问“我该怎么做……”)。将上次更新时间添加到 中可能会很好pg_stat_...,但是您必须让社区相信这些开销是值得的,或者提供一种方法来使其有选择地跟踪 - 而且您必须编写代码以保留统计信息和提交补丁,因为只有想要这个功能的人才会为此烦恼。

我该怎么做

如果我必须这样做,并且没有时间编写补丁来正确执行此操作,我可能会使用上面概述的侦听/通知方法。

PostgreSQL 9.5 提交时间戳更新

更新:PostgreSQL 9.5 有提交时间戳。如果你有他们启用了postgresql.conf(和过去一样也是如此),你可以检查提交时间戳以最大的行xmin近似的最后修改时间。这只是一个近似值,因为如果最近的行已被删除,它们将不会被计算在内。

此外,提交时间戳记录仅保留有限的时间。因此,如果您想知道何时修改了一个没有太多修改的表,那么答案实际上是“不知道,不久前”。


Thi*_*mal 20

PostgreSQL 9.5 让我们可以跟踪上次修改的提交。

  1. 使用以下查询检查轨道提交是打开还是关闭

    show track_commit_timestamp;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果它返回“ON”,请转到第 3 步,否则修改 postgresql.conf

    cd /etc/postgresql/9.5/main/
    vi postgresql.conf
    
    Run Code Online (Sandbox Code Playgroud)

    改变

    track_commit_timestamp = off
    
    Run Code Online (Sandbox Code Playgroud)

    track_commit_timestamp = on
    
    Run Code Online (Sandbox Code Playgroud)
  3. 重启 PostgreSQL 服务器

  4. 重复步骤 1。

  5. 使用以下查询来跟踪上次提交

    SELECT pg_xact_commit_timestamp(xmin), * FROM  YOUR_TABLE_NAME;
    
    SELECT pg_xact_commit_timestamp(xmin), * FROM YOUR_TABLE_NAME where COLUMN_NAME=VALUE;
    
    Run Code Online (Sandbox Code Playgroud)

  • 您不必在步骤 2 中重新启动系统。只需重新启动该过程。例如`sudo service postgresql restart`。 (4认同)

小智 5

为了在客户端应用程序上维护某些表的缓存,我有几乎相同的要求。我说几乎,因为我真的不需要知道上次修改的时间,而只是为了检测自上次缓存同步以来是否发生了更改。

这是我的方法:

假设每个表上都有id(PK)、created_on(插入时间戳) 和updated_on(更新时间戳,可能为 NULL) 列,您可以

SELECT id,greatest(created_on,updated_on) FROM %s ORDER BY greatest(created_on,updated_on) DESC LIMIT 1;
Run Code Online (Sandbox Code Playgroud)

如果将其连接起来并在前面添加行数,则可以构建一个类似于 的版本标记count:id#timestamp,并且对于表中数据的每个版本来说它都是唯一的。