Monotonic Last Modified Columns in Postgres
December 2nd, 2024Tracking a record’s last modified time is a common application requirement. In Postgres, a typical implementation
might look like this, using a BEFORE UPDATE
trigger on a last_modified_at
column:
CREATE TABLE foo (
id SERIAL PRIMARY KEY,
name TEXT,
last_modified_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE OR REPLACE FUNCTION update_last_modified_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.last_modified_at = now();
RETURN NEW;
END;
$$ LANGUAGE 'plpgsql';
CREATE TRIGGER update_last_modified_at_trigger
BEFORE UPDATE ON foo
FOR EACH ROW
EXECUTE PROCEDURE update_last_modified_at();
This works in most cases, but breaks an assumption that’s likely made by the application: last_modified_at
isn’t
necessarily monotonically increasing, even if the system clock is. This can cause problems when the application uses
last_modified_at
as a watermark for processing changes.