I still trust relational systems for many core transactional paths. I recommend protecting OLTP first, reading changes safely, and building analytics from governed copies instead of punishing the source database.
The business story lives in the joins
Relational data is strongest when correctness depends on relationships that must stay true under change.
Where relationships carry the work
Relational data is strongest when correctness depends on relationships that must stay true under change.
Where relational truth lives
This is where I check whether the data can be trusted by the people who depend on it.
PostgreSQL, MySQL, SQL Server, Oracle, Aurora, Cloud SQL, AlloyDB, Spanner, SQL Server, Elasticsearch or OpenSearch for search projections.
Managed relational options
| Provider | Typical services |
|---|---|
| AWS | RDS, Aurora, DMS, Glue, Redshift, OpenSearch. |
| Azure | Azure SQL Database, Azure Database for PostgreSQL, Data Factory, Synapse, AI Search. |
| Google Cloud | Cloud SQL, AlloyDB, Spanner, Datastream, Dataflow, BigQuery. |
Transaction pattern to remember
For relational systems, I keep the transaction boundary visible because that is where correctness usually lives.
Google Spanner is the public large company reference for relational data at global scale: it keeps SQL and transactions while distributing data across regions. The lesson is not that every team needs Spanner; it is that relational guarantees still matter when money or ownership changes.
Order lifecycle example
I use the workflow to keep the idea honest: who acts, what can fail, and how the team knows it worked.
In an order platform, the order service owns relational tables. CDC publishes every insert and update into a stream. The analytics team builds order lifecycle tables, while support search indexes order id, customer email, and shipment state.
Constraint backed code
The code should teach the rule, not decorate the article.
select
o.order_id,
c.email,
p.captured_at,
s.shipment_status
from orders o
join customers c on c.customer_id = o.customer_id
join payments p on p.order_id = o.order_id and p.status = 'CAPTURED'
left join shipments s on s.order_id = o.order_id
where s.order_id is null
and p.captured_at < current_timestamp - interval '2 days';
The query finds orders with captured payments but no shipment after two days. The joins are not reporting decoration; they expose a broken business workflow.
Relational traps to watch
- Do not run heavy analytics directly on OLTP primaries.
- Capture deletes and schema changes in CDC.
- Keep referential meaning when denormalizing for search.