Why Relational Databases Are Absurd

Some things defy analogy. Relational databases with SQL are one of them.

We programmers are obsessed with preserving our source code. We use Git, a tool that never forgets. Every version, every typo, every parallel universe is captured—because Git understands time.

And yet, we build our most critical systems—those that hold your money, your identity, your future—on databases that forget everything by default. Relational databases with SQL.

Drop table reality

With a single SQL command like DROP TABLE Ledger, an entire financial history can disappear. We build systems—serious ones—that operate on this fragile principle. Systems that manage savings, pensions, invoices. And somehow, we accept that the data in these systems lives in a present tense so narrow it forgets the past by design. There’s no trace of what was—just what is.

Encapsulation and Other Disasters

Then there’s the beloved UPDATE Ledger ... which can have even more bizarre effects, seemingly at random, because we make decisions in an object-oriented language, where we try to hide data behind encapsulation. Encapsulation doesn’t protect anything—it just complicates updates, and then we feed the update statement with that data.

A Personal Banking Bug

Once, my bank accidentally withdrew 60,000 SEK (~$6,000) from my account. When I noticed, my bank representative kindly offered me a loan… of my own money. She looked at the transaction log and saw: “Transfer from Stefan’s account: 60,000 to Stefan’s savings account: 0” and expressed utter surprise. Eventually, I got 10,000 SEK in compensation about 24 hours later.

Absurd by Design

Now, to be fair, this issue was not caused by SQL but by an old CICS program (JavaEE from 30 years earlier). But the absurdity of SQL-based systems holds, as does the banking industry’s relationship with our money and the in-place-update insanity of relational databases.

SQL itself isn’t the problem. The absurdity lies in the databases it’s tied to.It’s the in-place-update-based databases, which is to say, all relational databases I know of, that are truly absurd.

Disappearing Ink and Hidden Copies

I cannot think of anything in the physical world that is this absurd. That’s why I struggle with analogies. It’s like writing important contracts in disappearing ink, but the ink only disappears from your version, while a hidden carbon copy remains under the table.

Forgetting What Must Be Remembered

And the absurdity of relational databases continues. Not only do relational databases forget things you tell them to, but they also actively try their very best to forget. And sure, it’s great that a database executes what it promises efficiently.

The absurd part is that we use them in places where we absolutely do not want to forget anything. You never, ever want to forget the contents of an accounting ledger. If you make a mistake, the law requires you to append a correction.

I don’t think there’s ever a case where we want to forget. Instead, we want to know that we deleted something. We want to be certain of it.

GDPR and the Paradox of Deletion

Even with GDPR and the right to be forgotten, you don’t want to forget—you want proof that something was erased. Otherwise, how can anyone trust you? How can they know you’re not just hiding the data?

And here’s where relational databases become truly ridiculous. Most databases are engineered in a way that ensures they absolutely remember everything they have ever “forgotten”. This makes the use of relational databases even more absurd.

The Forbidden Log

They are built on transaction logs that guarantee everything is always recorded. I think SQL Server uses Hekaton, PostgreSQL uses WAL, and MySQL uses Binlog. I have never heard the name of the similar technique for Oracle and DB2, but I believe they use similar technology.

And yet, you, as a programmer, DBA, or user, are NOT allowed to see the transaction log. Why? Because it contains deleted information, which must remain secret, but it is also crucial for the database to verify that data has been deleted or successfully written.

For a database to implement transactions correctly, it must know exactly when something was deleted or inserted, both in simple and parallel chronology, since operations happen simultaneously.

It’s great technology, and you’ve probably noticed that a database’s disk usage never actually shrinks.

So does this mean we can’t use SQL Server, PostgreSQL, MySQL, Oracle, or DB2 for applications storing personal data, since they can’t truly forget, at least not if we want to be compliant with GDPR?

Even if you delete data in the database, it still exists in the transaction log, simply because the database needs to be sure it was deleted. The data is there, even if no one can see it.

You can even physically find it on disk. On a journaled filesystem, you need special functions to ensure real physical deletion.

Time as a First-Class Citizen

But then we have databases that make the transaction log explicit. I think Aurora, CockroachDB or FoundationDB show that approach. Some even promise to always show what was deleted and when, like I believe my favourite does: Datomic. Here, you can always see the entire history of any field over time, even in parallel timelines, since time is a variable in its query language. A query with two time-variables lets you analyze how data changed across different perspectives. It’s a bit like losing your mind in Git.

You can physically delete data in Datomic. It’s slow but secure, unless, of course, your backing store is a relational database. The use of relational backing store is common, as they are common.

Why Isn’t Datomic the Default?

So why aren’t all databases like Datomic? I have no idea. And when I think about what problems it solves, it becomes even harder to understand.

Data That Answers Back

I have used Datomic professionally in two projects. Here people were worried that we weren’t storing enough data, a common question in systems built on immutable data models:

“Can we answer any unknown question in the future?”

Meanwhile, in relational database land, people don’t ask anything at all, until data disappears. And when that happens, they run around like panicked chickens, assuming the world is ending. Everything is broken. The system is at fault. People demand answers. And yet, somehow, they calm down, not because they find a real explanation, but because they mitigate this in an even more absurd way, or because they simply accept that it’s too late.

Sometimes, the event is even seen as normal, like the moon suddenly falling into a lake.

Meanwhile, in a database that never forgets, people just… look at the data. They realize the actual program was wrong. They fix the code and tell the database the data is still there. And life moves on. I don’t understand why people don’t find that harmonious.

This has nothing to do with SQL. It’s about the entire database model. Of course, we don’t use SQL to query a Datomic database, just like we don’t use SQL to query Git. Instead, we use simpler query languages, such as Datalog (a subset of Prolog), and even simpler languages for looking up data like in tree structures.

Writing to the database is about describing what should go into the transaction log, based on conditions already present in it. It couldn’t be simpler. Datomic is a triple store, like RDF, and effectively serves as a relational database, key-value store, and document store—all at the same time. And data only disappears logically. If you look at what happened before the transaction where my name became Stefan, you will see that I was called something else before that.

Reactive Truth

Applications using this kind of database can subscribe to the transaction log and automatically receive updates within milliseconds. In one of my projects, we sent a filtered subset of the transaction log to a web application via WebSockets. That web app barely needed to query anything. It was just continuously up to date.

Distribution Shouldn’t Mean Amnesia

In today’s cloud-native, distributed systems, the fragility of mutable, in-place state becomes not just absurd but dangerous. Yes, distributed systems are hard. That’s exactly why I find it absurd that we continue to use relational databases in these environments. Databases like Datomic make this much easier by embracing a model that naturally aligns with CAP—something traditional databases struggle with.

Designed for Distributed Reality

Datomic’s architecture is built for distributed reality. It lets you use AP-tolerant backing stores like DynamoDB or Cassandra while still maintaining strong consistency through serialized writes. There’s no competition for locks, no need for distributed coordination across nodes—every write is ordered and safe by design. At the same time, availability remains high because queries run against immutable data that can be freely cached without risk of inconsistency.

Forgetting as Default

Sagas exist because we’ve built systems on mutable, ephemeral, transactional databases—systems that assume forgetting is the default. Instead of patching RDBMS with patterns like Sagas, databases like Datomic have data integrity as their foundation. When things go wrong, you don’t need to undo or compensate by reversing a failed transaction. You just add new facts. The past isn’t erased; it’s simply expanded upon. Eventual consistency isn’t a workaround—it’s built in. So we recreate what already exists—adding audit trails and event tables—because the system’s brain is off-limits.

Layers of Workaround

The Outbox pattern exists because relational databases can’t query their own transaction log. They hide that crucial part of reality from you, so you have to create an extra table just to capture what the database is already writing internally. In Datomic, that problem disappears—you simply query the transaction log directly. The database itself is an event stream. We buried simplicity beneath layers of forgetting. Datomic just remembers.

Is Datomic Really That Complicated?

And yet, people call Datomic complicated. But what’s complicated about a single transactor that serializes writes? The application layer fetches data directly from the backing store, and because all data is immutable, it can be safely cached locally without invalidation nightmares. There’s no heavyweight query parser—Datalog queries are just data structures.

Relational databases, on the other hand, are incredibly complex—they kind of work like Datomic in the core, using a transaction log to ensure correctness. But instead of exposing that truth, they hide it from you and then work hard to forget everything. And then we layer Sagas, Outbox tables, compensating transactions, orchestration, and other workarounds on top—just to recover what the system erased.


All #art #clojure #csharp #data-structures #database #datomic #emacs #functional #haskell #history #immutability #java #jit #jmm #lambdas #lisp #pioneers #poetry #programming #programming-philosophy #randomness #rant #reducers #repl #smalltalk #sql #threads #women