What Is a Data-Intensive Application?
Why most applications are limited by data rather than CPU, and how databases, caches, search indexes and logs fit together into one system that your code has to keep consistent.
Overview
An application is data-intensive when its hard problems are about data: how much there is, how complex it is, and how fast it changes. It is compute-intensive when the hard problem is raw CPU work, such as encoding video or training a model. Most business software (shops, social apps, banking, SaaS) is data-intensive. The CPU is rarely the limit; storing, finding and moving data correctly is.
Such an application is almost never one database. It is several specialized tools wired together, and your code is the wiring. That wiring is where most of the difficult bugs live, because each tool keeps its own promises and none of them promises anything about the others.
The building blocks
Each tool is good at one access pattern and gives something up to be good at it. Knowing what each one gives up is the skill interviewers look for, more than knowing product names.
- Database — Store data durably, answer queries, run transactions — PostgreSQL, MySQL — Slower than memory; full-text relevance ranking is not its strength
- Cache — Answer hot reads from memory — Redis, Memcached — Can serve old data; may lose recent writes on a crash
- Search index — Find records by words and rank them — Elasticsearch, OpenSearch — New writes show up after a short delay; not a system of record
- Log or message broker — Carry events between services, in order, and keep them for replay — Kafka — Not a query engine; consumers must process events themselves
- Stream or batch processor — Compute new data from old data — Flink, Spark — Results lag behind the input
- Analytics warehouse — Scan and aggregate huge tables — BigQuery, Snowflake — Not built for many small, fast writes
Two rows are worth making concrete. By default, Elasticsearch makes a new document searchable within about one second, because it refreshes an index once a second rather than on every write (and only while the index is being searched). Redis with snapshot persistence can lose the last few minutes of writes if it stops without a clean shutdown; with its append-only log at the default setting of one flush per second, it can lose about one second of writes.
One application, many stores
A typical design keeps one system of record (the place where a fact is first written and which wins in any disagreement) and builds everything else from it.
Source data and derived data
Everything in the picture is one of two kinds of data. Source data is the original. Derived data is computed or copied from it: a cache entry, a search index, a materialized view, a report. If derived data is lost, you can rebuild it from the source. If source data is lost, it is gone.
- Examples — Orders table, user accounts — Cache entries, search index, counters, reports
- If it is lost — Data loss; restore from backup — Rebuild it from the source
- If it disagrees with the other — It wins — It is stale and must be fixed
- Main risk — Losing writes — Going out of date without anyone noticing
Labeling every store in a design as source or derived is a quick way to show an interviewer you understand where truth lives.
The glue is your code
When the application writes to two systems itself (a dual write), each write can succeed or fail on its own, and two writers can interleave. Nothing makes the pair atomic. The sequence below shows one common way a search index ends up permanently wrong.
The usual fix is to write only to the system of record and let every other store follow its ordered change log (change data capture, or an event log such as Kafka). Kafka fits this role because consumed events are not deleted: each topic keeps them for a configured retention time, so a new index can be built by replaying the log, as long as retention (or log compaction) still holds the history it needs.
- Dual write from the app — App writes the database, then the cache or index — Races and partial failures leave them different
- Cache invalidation — App writes the database, then deletes the cache key — A read can refill the cache with an old value between steps
- Change data capture or event log — Stores follow the database's ordered change stream — Derived stores lag by a short, measurable delay
- Periodic rebuild — Recompute derived data from scratch in a batch — Data is only as fresh as the last run
The three questions every design answers
Once you have many parts, three questions decide whether the whole thing works. They are the subject of the next topics.
- Reliability — Does it keep giving correct answers when parts fail or people make mistakes? — Error rate, data loss, time to recover
- Scalability — When load grows, can we add resources and keep performance steady? — Throughput, latency percentiles
- Maintainability — Can many engineers run and change it for years without fear? — Time to ship changes, incidents per deploy
What you will be able to do
- Say whether a system is data-intensive or compute-intensive, and why that shapes the design.
- Name the job and the weakness of each common building block.
- Mark each store in a design as source or derived, and say how derived stores are rebuilt.
- Explain why dual writes go wrong and what to use instead.
Key concepts
- Data-intensive application
- An application whose main problems are the amount, complexity or rate of change of its data, not CPU speed.
- System of record
- The store where a fact is first written. When stores disagree, it is right and the others are wrong.
- Derived data
- Data computed or copied from the system of record, such as a cache, search index or report. It can be rebuilt from the source.
- Dual write
- The application writing the same change to two systems itself. The two writes are not atomic, so failures and races leave the systems different.
- Change data capture
- Reading the ordered stream of changes from a database so that other systems can apply the same changes in the same order.
- Access pattern
- How data is read and written: by key, by range, by text, by scanning and aggregating. Each store is built for a few patterns.
When to use it
- Opening a system design answer by listing the data systems the product needs and the access pattern each one serves.
- Explaining why an application uses a database, a cache and a search index instead of one store.
- Deciding which store is the system of record and how the others are kept in step with it.
- Reviewing a design for dual writes that can leave stores permanently out of step.
Interview questions
- Why do real applications use several data stores instead of one?
- How would you keep a search index in sync with the primary database?
- What is derived data, and why does the distinction matter in a design?
- Is it ever right to use a single database for everything?
Sign up free to read the full topic
More DDIA topics
Start free on Cariara · Coding problems · System design studio