Subject: Re: Re[2]: [PATCH] Add last_executed timestamp to pg_stat_statements

From: Sami Imseih <[email-masked]>
Date: Tue, 3 Feb 2026 20:37:31 -0600

> > I wonder if we can use GetCurrentStatementStartTimestamp()
> > instead?
>
> The main use case for this column is being able to retrieve the stats
> that were updated since the last time one was looking. That only works
> if it's the statement end time, or else long-running statements
> spanning more than one poll interval would be missed.

Sure, I get it is not perfect for the polling use-case due to the scenario
you mention,  but I don't think it will be acceptable to call
GetCurrentTimeStamp() at the end of every execution and especially
with a SpinLock held.

This will probably be worse for nested_tacking as well, due to
multiple GetCurrentTimeStamp() calls.

What do you think?

--
Sami Imseih
Amazon Web Services (AWS)

---

From: Bertrand Drouvot <[email-masked]>
Date: Wed, 4 Feb 2026 09:00:18 +0000

Hi,

> GetCurrentTimeStamp() at the end of every execution and especially

I think the same, that would not match (lmgr/README):

"
* Spinlocks.  These are intended for *very* short-term locks.  If a lock
is to be held more than a few dozen instructions, or across any sort of
kernel call
"

Out of curiosity I looked for GetCurrentTimeStamp() calls while holding a spinlock
and found one in WalReceiverMain(). But I guess it's less of an issue since
it's only called when the walreceiver starts.

Regards,

-- 
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

---

From: Pavlo Golub <[email-masked]>
Date: Thu, 5 Feb 2026 18:35:27 +0100

Hi all,

Thank you to Sami, Christoph, and Bertrand for the thorough review and valuable
feedback on v1. I've prepared a v2 patch that addresses all the concerns raised.

You're absolutely right that calling `GetCurrentTimestamp()` while holding a
spinlock is unacceptable.

I've adopted Sami's suggestion to use `GetCurrentStatementStartTimestamp()`
instead. While Christoph correctly points out that this means we're capturing
statement start time rather than end time, I believe this is an acceptable
trade-off for several reasons:
- the vast majority of statements complete quickly (well under typical polling
   intervals of 1-5 minutes);
- long-running queries will appear in the next poll anyway;
- deferring timestamp updates adds significant complexity;
- and most importantly zero performance overhead vs a kernel call per execution.

For the monitoring use case, what matters is knowing has this statement been
active since my last poll? The start time serves this purpose effectively.

I've renamed the column to `stats_last_updated` as Christoph suggested. This
matches the existing "stats_since" column for consistency. Following Christoph's
suggestion, I've also moved it to the end of the view.

Per Sami's feedback, I've moved the timestamp from the `Counters`
struct directly
to `pgssEntry`. This is more semantically correct since it's metadata about the
entry rather than a statistical counter.

I've updated `PGSS_FILE_HEADER` to 0x20260205.

Among other changes:
- fixed all whitespace errors
- moved tests to `entry_timestamp.sql` as suggested
- added documentation notice about nested statement behavior
- the timestamp is now set outside the spinlock-protected section

Sami mentioned this was discussed in 2017 [0]. Looking at that thread, the main
concerns were overhead and use cases. I believe we've addressed both:
- zero overhead by using existing statement start timestamp
- clear, documented use case from production monitoring tools (pgwatch, etc.)

[0] https://www.postgresql.org/message-id/flat/CA+TgmoZgZMeuN8t9pawSt6M=[email-masked]

I've attached the v2 patch. All existing tests pass.

I'd appreciate further review and feedback.

Thanks,
Pavlo Golub

---

From: Sami Imseih <[email-masked]>
Date: Thu, 5 Feb 2026 15:23:46 -0600

> feedback on v1. I've prepared a v2 patch that addresses all the concerns raised.

Thanks for the patch! I have not looked at v2 in detail yet. Did take
a quick peek

> suggestion, I've also moved it to the end of the view.

I still wonder if "stats_last_updated" is a good name here. What about
"last_execution_start", since that is exactly what this timestamp is.

+ <entry role="catalog_table_entry"><para role="column_definition">
+ <structfield>stats_last_updated</structfield> <type>timestamp with
time zone</type>
+ </para>
+ <para>
+ Time at which the statement statistics were last updated (specifically,
+ the time when the statement most recently started execution).

Here I think we can just say:

"The start time of the most recent execution of the statement that completed. "

+ This is useful for monitoring tools to identify which statements
+ have been executed since their last poll.

I am not sure we need this part for the docs. others may disagree.

+ For nested statements (when <varname>pg_stat_statements.track</varname>
+ is set to <literal>all</literal>), this reflects the start time of the
+ parent top-level statement.
+ </para></entry>

Maybe this is better as it mentioned "toplevel"

"For nested statements (toplevel = false), this reflects the start time
of the top-level statement."

what do you think?

---

From: "Pavlo Golub" <[email-masked]>
Date: Fri, 06 Feb 2026 10:44:58 +0000

Hey

>"last_execution_start", since that is exactly what this timestamp is.

Yeah, sounds better really. Thanks

>"The start time of the most recent execution of the statement that completed. "

+1

>I am not sure we need this part for the docs. others may disagree.

Agree, too much details.

>of the top-level statement."

I like it. Looks easier to read.

>what do you think?

Thanks, I'll prepare updated patch

---

From: Christoph Berg <[email-masked]>
Date: Fri, 6 Feb 2026 11:52:18 +0100

Re: Pavlo Golub
> Yeah, sounds better really. Thanks

I still believe that storing execution start time is the wrong thing
to do as it will miss all long-running statements. Consider this
timeline:

09:55 get all stats changed since 09:50
      -> doesn't see the statement because it hasn't started yet
09:57 start long-running statement
10:00 get all stats changed since 09:55
      -> doesn't see the statement because it's still running
10:02 long-running statement terminates, storing 09:57 as timestamp
10:05 get all stats changed since 10:00
      -> doesn't see the statement because it's too old

Christoph

---

From: Pavlo Golub <[email-masked]>
Date: Fri, 6 Feb 2026 16:27:00 +0100

OK, here is one more try. I discovered the `total_time` argument to
the `pgss_store()` function! So we can calculate the finish time
without calling `GetCurrentTimestamp()`.

This is version 3 of the patch adding a `stats_last_updated` column
(yes, again) to pg_stat_statements. Based on feedback, this version
improves the implementation with better performance and correctness.

The main improvement uses `statement_start + execution_duration` with
`rint(total_time * 1000.0)` to convert milliseconds to microseconds
with proper rounding. The calculation performed BEFORE acquiring
spinlock and assigned within locked scope.

I'm wondering how we all missed this trick from the very beginning and
started to argue if `GetCurrentTimestamp()` is heavy or not. :)

Best regards,
Pavlo