AS OF SYSTEM TIME
TheAS OF SYSTEM TIME timestamp clause causes statements to execute using the database contents "as of" a specified time in the past.
You can use this clause to read historical data (also known as "time travel queries") and to improve performance by decreasing transaction conflicts. SeeUseAS OF SYSTEM TIME to decrease conflicts with long-running queries.
Historical data is available only within the garbage collection window, which is determined by thettlseconds field in thereplication zone configuration.
Synopsis
TheAS OF SYSTEM TIME clause is supported in multiple SQL contexts, including but not limited to:
- In
SELECTclauses, at the very end of theFROMsub-clause. TheFORlocking clause isnot allowed withAS OF SYSTEM TIME. - In
BACKUP, after the parameters of theTOsub-clause. - In
RESTORE, after the parameters of theFROMsub-clause. - In
BEGIN, after theBEGINkeyword. - In
SET, after theSET TRANSACTIONkeyword.
AS OF SYSTEM TIME cannot be used with:
- Locking reads (
SELECT ... FOR UPDATEandSELECT ... FOR SHARE). - Mutation statements (such as
UPDATEorDELETE).
The preceding statements return an error:cannot execute {SQL STATEMENT} in a read-only transaction.
Parameters
Thetimestamp argument supports the following formats:
| Format | Notes |
|---|---|
INT | Nanoseconds since the Unix epoch. |
negativeINTERVAL | Added tostatement_timestamp(), and thus must be negative. |
STRING | ATIMESTAMP,INT of nanoseconds, or negativeINTERVAL. |
follower_read_timestamp() | Afunction that returns theTIMESTAMPstatement_timestamp() - 4.2s. Using this function will set the time as close as possible to the present time while remaining safe forexact staleness follower reads. |
with_min_timestamp(TIMESTAMPTZ, [nearest_only]) | The minimumtimestamp at which to perform thebounded staleness read. The actual timestamp of the read may be equal to or later than the provided timestamp, but cannot be before the provided timestamp. This is useful to request a read from nearby followers, if possible, while enforcing causality between an operation at some point in time and any dependent reads. This function accepts an optionalnearest_only argument that will error if the reads cannot be serviced from a nearby replica. |
with_max_staleness(INTERVAL, [nearest_only]) | The maximum staleness interval with which to perform thebounded staleness read. The timestamp of the read can be at most this stale with respect to the current time. This is useful to request a read from nearby followers, if possible, while placing some limit on how stale results can be. Note thatwith_max_staleness(INTERVAL) is equivalent towith_min_timestamp(now() - INTERVAL). This function accepts an optionalnearest_only argument that will error if the reads cannot be serviced from a nearby replica. |
To setAS OF SYSTEM TIME follower_read_timestamp() on all implicit and explicit read-only transactions by default, set thedefault_transaction_use_follower_readssession variable toon. Whendefault_transaction_use_follower_reads=on and follower reads are enabled, all read-only transactions use follower reads.
Although the following format is supported, it is not intended to be used by most users: HLC timestamps can be specified using aDECIMAL. The integer part is the wall time in nanoseconds. The fractional part is the logical counter, a 10-digit integer. This is the same format as produced by thecluster_logical_timestamp() function.
Examples
Select historical data (time-travel)
Imagine this example represents the database's current data:
>SELECTname,balanceFROMaccountsWHEREname='Edna Barath';+-------------+---------+| name | balance |+-------------+---------+| Edna Barath | 750 || Edna Barath | 2200 |+-------------+---------+We could instead retrieve the values as they were on October 3, 2016 at 12:45 UTC:
>SELECTname,balanceFROMaccountsASOFSYSTEMTIME'2016-10-03 12:45:00'WHEREname='Edna Barath';+-------------+---------+| name | balance |+-------------+---------+| Edna Barath | 450 || Edna Barath | 2000 |+-------------+---------+Using different timestamp formats
Assuming the following statements are run at2016-01-01 12:00:00, they would execute as of2016-01-01 08:00:00:
>SELECT*FROMtASOFSYSTEMTIME'2016-01-01 08:00:00'>SELECT*FROMtASOFSYSTEMTIME1451635200000000000>SELECT*FROMtASOFSYSTEMTIME'1451635200000000000'>SELECT*FROMtASOFSYSTEMTIME'-4h'>SELECT*FROMtASOFSYSTEMTIMEINTERVAL'-4h'Selecting from multiple tables
It is not yet possible to select from multiple tables at different timestamps. The entire query runs at the specified time in the past.
When selecting over multiple tables in a singleFROM clause, theASOF SYSTEM TIME clause must appear at the very end and applies to theentireSELECT clause.
For example:
>SELECT*FROMt,u,vASOFSYSTEMTIME'-4h';>SELECT*FROMtJOINuONt.x=u.yASOFSYSTEMTIME'-4h';>SELECT*FROM(SELECT*FROMt),(SELECT*FROMu)ASOFSYSTEMTIME'-4h';UsingAS OF SYSTEM TIME in subqueries
To enable time travel, theAS OF SYSTEM TIME clause must appear inat least the top-level statement. It is not valid to use it only in asubquery.
For example, the following is invalid:
SELECT * FROM (SELECT * FROM t AS OF SYSTEM TIME '-4h'), uTo facilitate the composition of larger queries from simpler queries,CockroachDB allowsAS OF SYSTEM TIME in sub-queries under thefollowing conditions:
- The top level query also specifies
AS OF SYSTEM TIME. - All the
AS OF SYSTEM TIMEclauses specify the same timestamp.
For example:
>SELECT*FROM(SELECT*FROMtASOFSYSTEMTIME'-4h')tpJOINuONtp.x=u.yASOFSYSTEMTIME'-4h'-- same timestamp as above - OK.WHEREx<123;UseAS OF SYSTEM TIME in transactions
You can use theBEGIN statement to execute the transaction using the database contents "as of" a specified time in the past.
>BEGINASOFSYSTEMTIME'2019-04-09 18:02:52.0+00:00';>SELECT*FROMorders;>SELECT*FROMproducts;>COMMIT;Alternatively, you can use theSET statement to execute the transaction using the database contents "as of" a specified time in the past.
>BEGIN;>SETTRANSACTIONASOFSYSTEMTIME'2019-04-09 18:02:52.0+00:00';>SELECT*FROMorders;>SELECT*FROMproducts;>COMMIT;UseAS OF SYSTEM TIME to recover recently lost data
It is possible to recover lost data as a result of an online schema change prior to whengarbage collection begins:
>CREATEDATABASEfoo;CREATE DATABASETime: 3ms total (execution 3ms / network 0ms)>CREATETABLEfoo.bar(idINTPRIMARYKEY);CREATE TABLETime: 4ms total (execution 3ms / network 0ms)>INSERTINTOfoo.barVALUES(1),(2);INSERT 2Time: 5ms total (execution 5ms / network 0ms)>SELECTnow(); now-------------------------------- 2022-02-01 21:11:53.63771+00(1 row)Time: 1ms total (execution 0ms / network 0ms)>DROPTABLEfoo.bar;DROP TABLETime: 45ms total (execution 45ms / network 0ms)>SELECT*FROMfoo.barASOFSYSTEMTIME'2022-02-01 21:11:53.63771+00'; id------ 1 2(2 rows)Time: 2ms total (execution 2ms / network 0ms)>SELECT*FROMfoo.bar;ERROR: relation "foo.bar" does not existSQLSTATE: 42P01Once garbage collection has occurred,AS OF SYSTEM TIME will no longer be able to recover lost data. For more long-term recovery solutions, consider taking either afull or incremental backup of your cluster.
Known limitations
- CockroachDB does not support placeholders in
AS OF SYSTEM TIME. The time value must be a constant value embedded in the SQL string.#30955 - The
ANALYZEalias ofCREATE STATISTICSdoes not support specifying anAS OF SYSTEM TIMEtimestamp.ANALYZEstatements useAS OF SYSTEM TIME '-0.001ms'automatically. For more control over the statistics interval, use theCREATE STATISTICSsyntax instead.#96430