TGMS keeps two clocks on every fact: when it was true, and when the system believed it. That idea is not ours. It has a forty-year literature, a place in the SQL:2011 standard, and production databases built around it — XTDB being the clearest example. Which raises the question this post answers: when we say bi-temporal, do we mean what they mean? We fed the same operation stream to both systems and probed their beliefs at four hundred points. They disagreed at none of them.
In one sentence
XTDB — a mature bi-temporal SQL database, doing its own SQL:2011 supersession over our raw operations — returns the same believed state as the TGMS native engine at 400 of 400 probe points across two correction densities at one million events; TGMS is 3.9–4.7× faster at correction-heavy ingest and 23–27× smaller on disk, and the agreement matters more than either ratio.
Why this matters
Bi-temporality is easy to claim and easy to get subtly wrong. A correction that arrives mid-transaction, a retraction that should truncate one version but not its later neighbours, a valid-interval carve that leaves a sliver believed that never should have been — every one of these is a place where two implementations can silently diverge while both calling themselves bi-temporal. Comparing against DuckDB or PostgreSQL cannot catch that: they execute the SQL we write, so they inherit whatever our semantics already say. Only a system with its own independent notion of the two clocks can contest ours.
That is also why this comparison exists at all. An external review of our evaluation said, correctly, that the bi-temporal claims had never faced a competitor that contests them. XTDB is that competitor: its whole identity is the thing we borrow.
The idea in plain language
The test discipline is the same one we use between our own backends: one operation stream, two systems, compare what they end up believing — never compare row layouts, because two correct bi-temporal stores may legitimately cut the same history into different fragments.
Two design choices make the comparison honest rather than decorative. First, XTDB receives our operations, not our resolved versions — it performs its own supersession, portion carving, and retraction handling in its own SQL dialect. Feeding it pre-resolved rows would test nothing but its B-trees. Second, our transaction clock maps onto XTDB's system time directly: XTDB's backfill mode accepts an explicit system time per transaction provided it never decreases, and our event log guarantees strictly increasing transaction times by construction. So "what did you believe at time T" is asked of both systems with no translation layer.
What we measured
What we found
Semantics first: zero disagreements. Every probe — current belief, valid-time as-of, transaction-time as-of, across corrections, carves, retractions, and the crafted in-batch scenario — returned the same believed state from both systems. The number we care most about in this whole comparison is that 0.
| operation | XTDB (5% / 20%) | TGMS native | ratio |
|---|---|---|---|
| current entity lookup | 2.15 / 2.80 ms | 0.037 / 0.014 ms | 58–200× TGMS |
| valid-time as-of | 2.13 / 3.89 ms | 0.028 / 0.010 ms | 76–389× TGMS |
| transaction-time as-of | 2.44 / 2.79 ms | 0.026 / 0.023 ms | 94–121× TGMS |
| one identity's full history | 5.45 / 3.46 ms | 0.137 / 0.126 ms | 28–40× TGMS |
| correction-heavy ingest (replay) | 411 / 1,788 s | 105 / 379 s | 3.9–4.7× TGMS |
| snapshot diff between two belief states | 51.5 / 49.1 ms | 21.1 / 20.7 ms | 2.4× TGMS |
| store on disk | 750.8 / 939.0 MB | 28.0 / 40.8 MB | 23–27× TGMS |
Two results we did not expect and report because they cut against easy narratives. XTDB is flat in correction density, just as we are — the "corrections degrade the competitor" story we might have hoped for is not true, and knowing that is worth as much as a win. And the point-lookup gap is partly deployment model rather than engine: TGMS runs embedded in the client process while XTDB serves a wire protocol from a JVM, so its ~2 ms floor includes costs an embedded library never pays. The ingest, diff, and storage ratios survive that caveat; the 389× does not deserve to be read at face value.
The comparison also audited us. While building it, two drafts of the harness accidentally timed non-idiomatic TGMS code paths that made XTDB look relatively better, and one idiom choice went the other way — the textbook bulk-insert pattern turned out 4.7× slower for XTDB than per-row prepared statements, so XTDB keeps the faster one. All three corrections are in the public commit history.
What this means in practice
What this result does not show
It does not show general superiority, and several cells remain unmeasured: edge-heavy operation timings, XTDB under configuration tuning beyond its recommended single-node image, and scale beyond one million events. The resource footprints were measured after the head-to-head and point the same way — XTDB reaches its first answer 12.75 s after container start (nearly all JVM-and-node boot) and holds 3.8 GB resident when warm, against 0.3–0.6 s and 176 MB for the embedded TGMS engine — but a server's boot and heap are the cost of being a server, not an engine verdict. The agreement result is bounded by the 400 + 140 probe points actually checked — probes are samples, not proofs. And the six operations here are storage semantics only: no graph traversal, no operator algebra, none of the agent-facing machinery. Those claims have different competitor classes and are evaluated separately.
Takeaway
Bi-temporality is inherited, not invented here — and the inheritance is faithful: the system whose identity is bi-temporality agrees with ours at every point we probed, while TGMS holds a 4× ingest, 2.4× diff, and 25× storage advantage on graph-shaped correction workloads.
Evidence and reproduction
Receipts benchmarks/results-v1/eval-xtdb-1m-{5,20}-final.json; harness scripts/xtdb_baseline.py (container lifecycle, op-level replay, probes, and the crafted in-batch scenario via --scenario d059); plan and per-cell forecast scoring in docs/eval_xtdb.md. XTDB image ghcr.io/xtdb/xtdb at the digest recorded in each receipt's manifest.
Continue reading
Prerequisite: why a correction is not an update — the two-clock model this whole comparison rests on. Next: where TGMS is fast and where specialists still win — the same correctness-gated discipline against five non-bi-temporal systems.