The Value of Bitemporality – Whose Time Is It Anyway?
juxt.pro
juxt.pro
I'd love to see someone translate the concepts in both books to a useful postgres package. As Snodgrass points out, "Unfortunately, due to the noncompliance of all existing DBMSs, a few of these fragments run on no existing platform" and thus only discusses how they can be applied to DB2, MSSQL, Sybase, Oracle8 and UniSQL.
This is some work on this. [1] is an amazing patch by some researchers in Europe that has already had several rounds of review. Their first published work was against Postgres 9.1! Their solution is way better than SQL:2011, but could be used behind-the-scenes to implement the features from the standard. Essentially they implement a temporal variant for every operator in the relational algebra (very elegantly btw, by combining standard operators with just two new functions). That approach solves some of the problems that led to Snodgrass's original temporal proposal getting rejected in the late 90s (and which are still holding back SQL:2011 IMO). Whereas the standard only gives temporal INNER JOIN, their work gives every join type, as well as aggregates (including a way to scale the inputs if the group only includes part of their time interval). It also lets queries compose better through subqueries, views, CTEs, set-returning functions, etc. In my opinion their work would make Postgres the most advanced temporal database in the world. I hope it gets the attention it needs!
I also have a very modest WIP patch myself at [2], which adds temporal-aware primary and foreign keys.
This is all based on the excellent work on ranges and exclusion constraints by Jeff Davis and others. Postgres has an excellent foundation, but needs the higher-level concepts so that users can more easily set up temporal tables and use them to answer queries and record changes.
If you'd like to learn more about temporal databases, I wrote a summary of the research at [3]. I'm also giving a talk at the Postgres conference in Ottawa next month.... :-)
EDIT: Btw, if all you need is transaction time (usually included for auditing and compliance), then the temporal_tables extension [4] should be all you need. Maybe also consider the pgaudit extension too [5].
[1] https://commitfest.postgresql.org/22/2045/
[2] https://commitfest.postgresql.org/22/2048/
[3] https://illuminatedcomputing.com/posts/2017/12/temporal-data...
It has its pain points, mostly related to how hackish the AR insertion is, but it works quite well and the approach ensures that any INSERT/UPDATE/DELETE triggers bookkeeping of the history tables.
For valid-time DML, I think the most useful operation is an upsert/merge. Tom Johnston calls this an `INSERT WHENEVER` I think. I have a not-yet-published Rails project that also uses INSTEAD OF triggers to convert AR saves to valid-time upserts. Hopefully I can get that published soon. I would love to even contribute it to Chronomodel eventually if that makes sense, so that it can be bitemporal.
Although there is tons of research in temporal relational database design, the rest of the stack really needs attention. What does temporal mean for REST and CRUD? Or your ORM? What are good UX patterns for viewing and editing a valid-time history? Can you make save-as-you-type work or do you need a Save button? I'd love to see people start working on that! My own Rails experiment landed on one way, and for me it validated that the db-level features would actually be useful, but there are other approaches possible.
We have a few custom tools to make them more ergonomic to create and update, but the core functionality is derived from an open source extension, I believe. Although, googling for it now, while away from my work computer, I can’t seem to find it... :/
... after looking it up on my work computer, it turns out we wrote our own implementation. It’s less than 200 lines of SQL, and uses three relatively common extensions. I wish it was open source, because it’d be super helpful to have in the future. But hey, at least it’s good to know that it can be/has been practically done?
It's definitely "heavier" than it needs to be – we store a lot of redundant data, but it hasn't been a huge issue.
But we have tools that build the tables/views, and generate sqlalchemy code, so that it's not difficult to manage, all told.
Our implementation is based on GIST with exclusion, and we have it in production for over a year by now. Zero performance problems, lots of gains from the business perspective.
Our code is here: https://github.com/scalegenius/pg_bitemporal
Another totally valid complaint of our implementation is that it makes Schema migrations a major pain. I wasn’t around when we made our extension, but if I had been, I probably would have recommended using yours :). I suspect that we did it our way because it was some combination of (1) the most straightforward to migrate our existing data towards (2) it was the easiest to hack together.
Anyways, thank you for sharing your project! I’m excited to use it at home, and maybe in the future at work!
- What was X's address 2 years ago?
- What did our database think X's address was 2 years ago, 3 months ago?
It's fundamentally impossible to answer those kinds of queries in a scalable way (parsing application logs is not a scalable way) without bi-temporal data.
I'd readily acknowledge that there are some types of data, for which having the capability to answer those queries is overkill. But, in the insurance industry, this kind of introspection is essential from both a compliance and correctness point of view.
Personally, if I were an auditor/government regulator for this industry, I would raise a big red flag over any critical data that wasn't bitemporal.
I would definitely vouch for its business necessity – so please, keep up your advocacy!! :)
I'm still working on a project which had been started around 2006 by Marc Kramis (his Ph.D. work) and where I began work on around 2007 :-) we borrowed quiet some ideas from ZFS mainly (as well as from Git now) and putted them to test on a sub-file level and added our own stuff as for instance record-level versioning via a sliding snapshot algorithm.
There's still a lot to do, but I'm able to store and query revisions of both XML as well as JSON now via XQuery and I'll look into (cost based) query optimizations and partitioning/replication next. I know that it has been probably crazy to write a storage manager from scratch, but I think Marc's ideas are pretty good and I added my own ideas and Sebastian Graf, another Ph.D. student back then also did a lot of work on the project, just as many other students. Maybe I'm just crazy to keep working on it almost daily now besides my day to day software engineering job, but yeah... I guess you have to be a bit too convinced and too dedicated to something, maybe (even though sadly I don't know if anyone tried it lately) ;-) maybe I need to contact Marc after all this time again :-)
https://sirix.io/concepts.html
http://pubsys.mmsp-kn.de/pubsys/publishedFiles/Kramis2014.pd...
I really hope to see other databases make it easier to use bitemporality in the near future, but I suspect that any DBMS which mandates a schema is fighting an up-hill battle.
Disclosure: working on Crux at JUXT :)
Disclosure: I work at JUXT but not directly on Crux
This question is confused, because it's taking a derived property as fundamental. It takes as fundamental the fact that there are two associated times, rather than as fundamental the fact that there are these particular associated times, of which there happen to be two. If you can't think of a particular third associated time to add, the idea of "going to three" is meaningless on its own.
I think branching/merging itself wouldn't be that hard to implement, at least if you have a versioned index at the very core (disclaimer: I'm also developing an Open Source temporal storage system). But then you'd have checkouts, handling conflicts...
SELECT person AS OF t1 FROM upstream AS OF t2
Which reconstructs the view that our upstream source would have constructed for a particular time (t1) from its perspective at a different time (t2). JOIN event_feed_1 AS OF t1 AND event_feed_2 AS OF t2
There’s various reasons you need to offset the comparison of two event feeds, such as their clocks not matching.But a different question is whether the system can do something useful for you with first-class time co-ordinates, compared to just stuffing additional timestamps into your data. (something useful being clever indexing, compaction, maybe more?)
#1: Keep rows immutable. Don't use UPDATE or DELETE.
#2: Store the time columns you need, e.g. insertion or transaction time, and/or event generation time, etc.