添加列和触发器真的很安全
虽然我意识到您已经说过它是生产数据库中的一个大表,所以您说您不能修改它,但我想解释一下如何进行影响非常低的更改。
在 PostgreSQL 中,一个ALTER TABLE ... ADD COLUMN
可为空的列只需要一些时间,并且不需要重写表。它确实需要一个独占锁,但其主要结果是它可能需要很长时间ALTER TABLE
才能真正进行,它在等待获得锁的机会时不会阻止其他任何事情。
在表上创建触发器也是如此。
这意味着添加modified_at
orcreated_at
列和关联的触发器函数以将它们维护到在现实世界中密集使用的活动表中是非常安全的。在创建列之前添加的行将为空,这很有意义,因为您不知道何时添加/修改它们。每当行更改时,您的触发器将设置该modified_at
字段,因此它们将逐渐被填充。
出于您的目的,拥有一个触发器维护的边表可能更有用,它跟踪表中任何位置的最后一次更改(插入/更新/删除)的时间戳。这将使您免于在磁盘上存储一大堆时间戳,并让您发现何时发生删除。使用触发器在每次更改时更新一行的单行边表FOR EACH STATEMENT
成本非常低。由于争用,对于大多数表来说这不是一个好主意 - 它本质上会序列化所有尝试在行更新锁上写入表的事务。在您的情况下,这可能很好,因为表很大并且很少更新。
第三种选择是让侧表累积插入/更新/删除语句甚至单个行的时间戳的运行日志。这允许您的客户端读取更改日志表而不是主表,并对其缓存数据进行小幅更改,而不是使整个缓存失效并重新读取。缺点是您必须有办法定期清除旧的和不需要的更改日志记录。
所以......你不能改变桌子真的没有操作上的理由。尽管您知道这样做很安全,但很可能有商业政策原因阻止您这样做。
...但如果你真的,真的,真的不能:
另一种选择是使用现有的“md5agg”扩展:http ://llg.cubic.org/pg-mdagg/ 。或者,如果您是从源代码构建的,则应用当前流行的 pgsql-hackers 补丁将“md5_agg”添加到您的 PostgreSQL 安装的下一个版本。
逻辑复制
PostgreSQL 项目的双向复制产生的功能允许您侦听和重放逻辑更改(行插入/更新/删除),而无需对表进行触发器。pg_receivellog 工具在包含一些脚本时可能会很好地满足您的目的。
缺点是你必须运行一个修补过的 PostgreSQL 9.3,所以我猜如果你不能改变一个表,运行一堆将来可能会不兼容地改变的实验代码不会很高你的优先级列表;-)。它包含在 9.4 的库存版本中,请参阅“变更集提取”。
测试 relfilenode 时间戳不起作用
您可能认为您可以查看支持磁盘上表的文件的修改时间戳。这不会很有用:
- 该表被拆分为多个扩展区,默认情况下每个文件为 1GB。因此,您必须在所有这些中找到最新的时间戳。
- Autovacuum 活动将导致这些时间戳发生变化,可能在相应的写入发生后很长一段时间。
- Autovacuum 必须定期对表内容进行自动“冻结”,以防止事务 ID 回绕。这涉及逐步重写表,并且自然会更改时间戳。即使在很长一段时间内没有添加任何内容,也会发生这种情况。
- 提示位设置会导致
SELECT
. 这些写入也会影响文件时间戳。
检查事务日志
理论上,您可以尝试解码事务日志pg_xlogreader
并找到影响感兴趣表的记录。您必须尝试排除由真空引起的活动、提示位设置后的整页写入,当然还有整个数据库集群中每个其他表的大量活动。
这对性能的影响可能是巨大的,因为必须检查对整个系统上每个数据库的每次更改。
总而言之,相比之下,在表上添加触发器是微不足道的。