Chapter 01 · Data Warehouse Foundations: OLTP vs OLAP, Analytical Workloads, Architecture, and Lab Dataset

Operational vs Analytical Systems: Transaction Shape, History, Concurrency, Query Complexity, and Data Freshness

Contrast operational and analytical workload mechanics with a deterministic AtlasMart source fixture, history and freshness contracts, and reconciled analytical queries.

Intermediate → Advanced100–120 minutesLocal synthetic evidence labPython sqlite3 · version recorded at runtimeLast reviewed: September 2026

Learning outcomes

AtlasMart's checkout service is optimized to find and change a few rows quickly, but finance and operations also need questions such as “paid merchandise value by day and customer segment” across months of history. The same data participates in both workloads, yet the access pattern, concurrency profile, history requirement, and acceptable freshness are different. This lesson makes those differences observable before any warehouse schema is designed.

01

Contrast OLTP and OLAP by transaction shape, concurrency, history, query complexity, and freshness without treating either label as an absolute product category.

02

Explain why an operational schema can be correct for order processing yet awkward or risky as the direct source for broad BI queries.

03

Distinguish current operational state, historical analytical evidence, source commit time, extraction time, load time, and consumer-visible freshness.

04

Run a deterministic AtlasMart fixture and reconcile the analytical result to source control totals.

05

Recognize when a proposed “warehouse” is merely a read replica or reporting query pointed at the transactional system.

Lab boundary

The mandatory lab uses Python’s standard-library sqlite3 module and synthetic data. It is a semantic/query-shape exercise, not a benchmark of SQLite versus any warehouse engine. Record the Python and SQLite versions printed by the script; do not generalize local timings to a production platform. All timestamps are UTC.

1. Start with workload shape, not database labels

Online transaction processing (OLTP) describes workloads dominated by many small, bounded operations that maintain operational state: place an order, change a shipping address, reserve inventory, or read one account. Correctness under concurrent writes and predictable response for short transactions usually matter more than scanning years of history.

Online analytical processing (OLAP) describes workloads that read and combine substantial data to answer business questions: revenue trends, cohort behavior, fulfillment latency, inventory exposure, or variance to plan. Queries are commonly read-heavy, aggregate many rows, and may join several business subjects. They often tolerate data that is seconds, minutes, or hours behind the source if that delay is explicitly contracted.

Dimension Operational tendency Analytical tendency Important caveat
Unit of work Point lookup or short write transaction Scan, join, group, window, or exploration Real systems mix both shapes.
Concurrency Many simultaneous users/services changing state Fewer but heavier readers/transform jobs A dashboard burst can still create high analytical concurrency.
History Current state is central; audit/history may be separate Historical reconstruction is usually first-class OLTP systems can retain history; warehouses can also serve current-state views.
Schema pressure Integrity and efficient state changes Understandable slicing, grouping, and stable semantics Logical modeling and physical layout are separate decisions.
Freshness Usually immediate for the transaction just committed Defined by pipeline and serving SLO “Realtime” is not a synonym for “correct.”

The distinction is therefore a workload model, not a rule that one product can only perform one class of query. Chapter 17 and later courses will examine physical engines; Chapter 01 is concerned with semantics and responsibility boundaries.

2. One operational request touches little data; one analytical question can touch a lot

Consider AtlasMart order O1003. The checkout service can retrieve its current status by primary key. That request has a narrow predicate and returns one row. Finance instead asks for paid merchandise value by day and customer segment. The analytical question joins orders to line items and customers, filters by business status, groups, and sums measurements. Both queries are valid, but their computational footprints and failure consequences differ.

Operational point lookup
SELECT status, updated_atFROM ordersWHERE order_id = 'O1003';
Analytical aggregation
SELECT  substr(o.order_ts, 1, 10) AS order_date,  c.segment,  SUM(ol.quantity * ol.unit_price) AS paid_gmv,  COUNT(DISTINCT o.order_id) AS paid_ordersFROM orders AS oJOIN order_lines AS ol USING (order_id)JOIN customers AS c USING (customer_id)WHERE o.status = 'paid'GROUP BY 1, 2ORDER BY 1, 2;
order_date segment paid_gmv paid_orders
2026-09-18 Consumer 200 1
2026-09-18 SMB 125 1
2026-09-19 SMB 150 1
2026-09-20 Consumer 150 1

The grouped result must reconcile to the source fixture: paid merchandise value is 625 across 4 paid orders. All line-item value, including the pending order, is 1025. The 400 difference is explained by the business filter, not by missing data.

3. History is a contract about what can be reconstructed

An operational customers row can be updated from segment SMB to Enterprise. If the old value is overwritten and no change history exists, a later analyst cannot prove what segment AtlasMart believed the customer belonged to when an earlier order was placed. Warehousing therefore treats historical meaning as a deliberate requirement rather than assuming the source’s current row is enough.

This does not mean every warehouse must preserve every field forever. It means each analytical attribute needs a stated policy: overwrite, preserve versions, take periodic snapshots, derive from immutable events, or deliberately keep only current state. Slowly changing dimensions and effective dating are taught in Chapter 07. Here, the important mechanism is that historical questions require historical evidence.

4. Freshness is a timestamp chain, not a marketing adjective

For a record committed at the source at 10:00 UTC, an extract might observe it at 10:10, a transformation might publish it at 10:14, and a certified dashboard might refresh at 10:20. The consumer-visible freshness lag is then 20 minutes. A pipeline can run every five minutes and still miss a 15-minute freshness objective if source extraction, transformation, queueing, or BI cache time dominates.

Timestamp Meaning Owned by
event_time When the business event occurred Business/source semantics
source_commit_time When the source made the change durable/visible Operational source
extract_or_capture_time When ingestion observed the change Ingestion
warehouse_load_time When the analytical state was committed Transformation/warehouse
consumer_available_time When certified data became queryable/visible Serving/BI path
Freshness rule

Always state which two timestamps define a freshness metric. “The pipeline is near-real-time” is not measurable until the start event, end event, percentile or maximum, and observation window are defined.

5. Controlled failure: run BI directly against the checkout schema

A tempting shortcut is to connect a dashboard to the transactional database and let analysts issue unrestricted joins. With the tiny fixture this appears efficient: there are only five orders. At production scale, however, unbounded scans compete with checkout traffic, schema changes made for application needs can break dashboards, current rows may not preserve historical meaning, and business metrics become duplicated across reports.

The repair is not “copy everything once per night” by reflex. The repair is to separate responsibilities: define analytical questions and freshness, capture source evidence, isolate heavy analytical work from operational write paths, preserve required history, and expose governed metrics. The appropriate batch/CDC and physical architecture are chosen from those requirements later.

6. Hands-on lab — build the source fixture and prove the control totals

Create an empty directory. Save the following as setup_atlasmart.py and run it with a local Python interpreter. The script deletes only atlasmart_oltp.db in the current directory, prints the runtime versions, creates the synthetic source database, and reports row counts.

setup_atlasmart.py
from pathlib import Pathimport sqlite3, sysDB = Path("atlasmart_oltp.db")if DB.exists():    DB.unlink()con = sqlite3.connect(DB)print("Python:", sys.version.split()[0])print("SQLite:", sqlite3.sqlite_version)con.executescript(r'''PRAGMA foreign_keys = ON;CREATE TABLE customers (  customer_id TEXT PRIMARY KEY,  customer_name TEXT NOT NULL,  segment TEXT NOT NULL,  region TEXT NOT NULL,  updated_at TEXT NOT NULL);CREATE TABLE products (  product_id TEXT PRIMARY KEY,  product_name TEXT NOT NULL,  category TEXT NOT NULL,  list_price NUMERIC NOT NULL,  updated_at TEXT NOT NULL);CREATE TABLE orders (  order_id TEXT PRIMARY KEY,  customer_id TEXT NOT NULL REFERENCES customers(customer_id),  order_ts TEXT NOT NULL,  status TEXT NOT NULL,  channel TEXT NOT NULL,  updated_at TEXT NOT NULL);CREATE TABLE order_lines (  order_id TEXT NOT NULL REFERENCES orders(order_id),  line_no INTEGER NOT NULL,  product_id TEXT NOT NULL REFERENCES products(product_id),  quantity INTEGER NOT NULL CHECK (quantity > 0),  unit_price NUMERIC NOT NULL CHECK (unit_price >= 0),  PRIMARY KEY (order_id, line_no));CREATE TABLE inventory (  product_id TEXT PRIMARY KEY REFERENCES products(product_id),  on_hand INTEGER NOT NULL CHECK (on_hand >= 0),  snapshot_ts TEXT NOT NULL);INSERT INTO customers VALUES('C001','Ada Retail','SMB','North','2026-09-20T08:00:00Z'),('C002','Ben Home','Consumer','West','2026-09-20T08:00:00Z'),('C003','Cyra Labs','Enterprise','East','2026-09-20T08:00:00Z'),('C004','Dara Studio','Consumer','South','2026-09-20T08:00:00Z');INSERT INTO products VALUES('P100','Keyboard','Accessories',50,'2026-09-20T08:00:00Z'),('P200','Mouse','Accessories',25,'2026-09-20T08:00:00Z'),('P300','Monitor','Displays',200,'2026-09-20T08:00:00Z'),('P400','Dock','Accessories',100,'2026-09-20T08:00:00Z');INSERT INTO orders VALUES('O1001','C001','2026-09-18T09:15:00Z','paid','web','2026-09-18T09:16:00Z'),('O1002','C002','2026-09-18T11:30:00Z','paid','mobile','2026-09-18T11:31:00Z'),('O1003','C001','2026-09-19T15:00:00Z','paid','web','2026-09-19T15:01:00Z'),('O1004','C003','2026-09-19T16:40:00Z','pending','sales','2026-09-19T16:40:00Z'),('O1005','C004','2026-09-20T07:10:00Z','paid','mobile','2026-09-20T07:11:00Z');INSERT INTO order_lines VALUES('O1001',1,'P100',2,50),('O1001',2,'P200',1,25),('O1002',1,'P300',1,200),('O1003',1,'P400',1,100),('O1003',2,'P200',2,25),('O1004',1,'P300',2,200),('O1005',1,'P100',1,50),('O1005',2,'P400',1,100);INSERT INTO inventory VALUES('P100',40,'2026-09-20T08:00:00Z'),('P200',60,'2026-09-20T08:00:00Z'),('P300',12,'2026-09-20T08:00:00Z'),('P400',25,'2026-09-20T08:00:00Z');''')con.commit()print({name: con.execute(f"SELECT COUNT(*) FROM {name}").fetchone()[0]       for name in ["customers", "products", "orders", "order_lines", "inventory"]})con.close()

Expected row-count evidence is {'customers': 4, 'products': 4, 'orders': 5, 'order_lines': 8, 'inventory': 4}. Then open the database with a SQLite-capable client or extend the script with the two SQL statements above.

Reconciliation assertions
SELECT SUM(ol.quantity * ol.unit_price) AS paid_gmv,       COUNT(DISTINCT o.order_id) AS paid_ordersFROM orders AS oJOIN order_lines AS ol USING (order_id)WHERE o.status = 'paid';-- expected: 625 | 4SELECT SUM(quantity * unit_price) AS all_line_valueFROM order_lines;-- expected: 1025SELECT SUM(on_hand) AS on_hand_unitsFROM inventory;-- expected: 137

Verification checklist: record Python/SQLite versions; confirm all five table counts; confirm paid GMV 625 and four paid orders; confirm all-line value 1025; confirm inventory 137 units; explain the 400 value excluded by the paid-status rule. These are deterministic fixture assertions, not performance measurements.

Cleanup: close database clients and delete only atlasmart_oltp.db and the local script from the lab directory.

7. Production judgment

Use operational systems to protect operational state and analytical systems to answer analytical questions under explicit history, freshness, quality, security, and cost contracts. The boundary can be implemented by separate products, separate clusters, replicas, shared storage, or managed services; Chapter 01 does not prescribe a vendor topology.

The next lesson names the common layers around that boundary—warehouse, mart, ODS, lake, lakehouse, semantic layer, and BI platform—so AtlasMart can stop using them as interchangeable words.

Knowledge check

Check your understanding

  1. Why is “OLTP vs OLAP” better understood as workload shape than as a strict product label?
  2. What does the 625 paid-GMV control total prove, and what does it not prove?
  3. Why can preserving only the current customer row make a historical analysis impossible?
  4. Which timestamps would you subtract to measure source-commit-to-dashboard freshness?
  5. Why is the local SQLite lab not evidence that SQLite is faster or slower than a cloud warehouse?
Review the answers

1. Because many engines can execute both kinds of work; the useful distinction is the transaction/query pattern, concurrency, history, latency, and operational consequence.

2. It proves that the analytical filter and aggregation reconcile to this synthetic source fixture. It does not prove a production metric definition, warehouse performance, or completeness of a real source.

3. An overwrite destroys the prior attribute value unless another history surface exists, so the system cannot reconstruct what was believed at the earlier event time.

4. Subtract source_commit_time from consumer_available_time, and state whether the SLO applies to a percentile, maximum, or another statistic over a defined window.

5. The lab intentionally controls semantics and expected results only. Engine performance depends on data volume, storage layout, cache, concurrency, hardware, optimizer behavior, and workload.

Summary and next step

Operational and analytical systems can share data without sharing the same workload contract. Keep transaction shape, history, query complexity, concurrency, and freshness explicit; preserve source control totals; and never convert a tiny local query into a performance claim.

Next: Warehouse, Data Mart, ODS, Data Lake, Lakehouse, Semantic Layer, and BI Platform: Responsibilities and Boundaries.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.