Bitemporal History
martinfowler.com
martinfowler.com
Pretty fun actually when you have billions of these records:)
Database kernels designed for first-class bitemporality support have low-level internal structures to optimize operations on bitemporal data models not found in typical database kernels. These features are not free if they aren't being used, hence why they are relatively rare in databases that are not explicitly bitemporal.
Also, Crux maintains a point-in-time (a.k.a timeslice) temporal index which is really a Z-Order Curve[0] that stores the two dimensions for fast lookups in a local KV store like RocksDB or LMDB. By contrast, a userland RDBMS implementation of bitemporality will be significantly slower to execute similar point-in-time "as-of" queries.
[0] https://en.m.wikipedia.org/wiki/Z-order_curve
(I work on Crux)
What I found was not great. So glad to see this idea getting a good write up.
I just hope that whatever systems get created (bitemporal history, version control, etc.) have support for "replacing" previous usernames, or deleting events prior to a specific "record time" and replacing them with newer understandings of history. Doing so in Git (a more-or-less append-only system) results in multiple histories which diverge at the moment of the change.
> In summary, the Crux indexes as a whole could be described as a "partially persistent and fully retroactive data structure".
[0] https://en.wikipedia.org/wiki/Retroactive_data_structure
[1] https://opencrux.com/articles/bitemporality.html#_retroactiv...
The trouble with these sorts of approaches is that they solve temporality the same way we did in the 90s: Add an `entity_history` table, timestamp your tx-time and valid-time, and add a trigger to version your entities. This must be done for each entity you want to version across your temporal plane.
It would appear that `temporal_tables` doesn't support bitemporality yet. It only has tx-time (system time). But even if it did, this approach doesn't help you with live data. Because the `entity` table corresponding to the `entity_history` table still permits destructive updates, temporal queries are always in the realm of audits and can't answer questions about the application data directly. Add to that a completely manual system of querying the temporal information, and the resulting systems tend to get quite hairy, which is why Martin recommends avoiding bitemporality whenever you can. Unfortunately, that recommendation (while sound, for relational databases) means that bitemporality is expensive and manual if and when it's implemented.
A bitemporal database like Crux encodes the temporal plane into all the data stored in it, making it transparent to the user. There's no up-front setup cost to bitemporality and a query's default time on both time axes is "now", allowing the user to ignore temporality entirely except in those few instances where it is required -- but when it is required, it is global.
As I understand it, most implementations (including another one for bitemporality[1]) involve either audit tables, as you mention, and/or additional support columns. It's as if the "now" representation is simply a narrowed view within the full set of underlying, (bi)temporal data.
That said, PostgreSQL encodes and has battle-tested decades of database functionality, including a surrounding ecosystem, so I'd be a little wary of switching technology even if it does solve one individual problem thoroughly. Everything has to start somewhere, though.
- system-versioned tables, which is the focus of this extension. This can be implemented purely database-side, and the application doesn't even need to know whether (certain) tables are system-versioned. This is mainly intended to offer change tracking and auditing in a standard way, to replace all the home-grown solutions to do the same.
- application-versioned tables, which I think Postgres already supports natively. This puts the application in control of the timespans in which a row is considered valid, and is probably what you would use for retroactive (or planned) updates to business records.
I'm not sure if the standard specifies how these two versioning systems interact, but by combining both strategies, you could in theory have a full system-versioned record of who made which changes to take effect on which date.