MindForge
MindForge
DashboardHelp & Support
Dashboard
MindForge

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
Choosing a Database: Storage, Indexes and Transactions
Course contents

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
Browsing without an account — progress is saved in this browser only.Sign in to save it

Choosing a Database: Storage, Indexes and Transactions

Reading50 min

"SQL or NoSQL?" comes up in almost every design interview. The answer that actually scores points is never a personal preference. It's a mapping from what your queries look like to which storage engine handles that shape best. This lesson walks through that mapping, what a database index actually is, why two common storage designs behave so differently, and the transaction guarantees you're already relying on, whether you know it or not.

Picking a store from the access pattern

Start from the questions you'll actually ask the database, not from whichever technology you've heard of.

If the workload is… Use Because
Related entities, varied queries, rules that span multiple rows Relational (Postgres, MySQL) Joins, constraints, real transactions, mature tools
Huge volume, a known key, simple lookups, very high write rate Wide-column (Cassandra, DynamoDB, HBase) Spreads writes across many machines, tunable correctness, no joins
Flexible, evolving records fetched as a whole Document (MongoDB, DocumentDB) Flexible shape, reads nested data without joins
Short-lived data, counters, leaderboards, sessions, queues In-memory (Redis) Sub-millisecond speed, useful built-in data structures
Full-text search, filters, ranking results by relevance Search index (Elasticsearch, OpenSearch) Built to search text quickly and score results
Time-stamped measurements at very high write rate Time-series (Timescale, InfluxDB, Prometheus) Compresses well, shrinks old data automatically, manages retention
Following relationships (friend of a friend of a friend) Graph (Neo4j) Follows connections directly, instead of joins that would explode
Large files that rarely change Object store (S3) plus a small database for details about each file Cheap, durable, works well with a CDN
Scanning billions of rows for analytics Columnar / warehouse (BigQuery, ClickHouse, Redshift) Reads only the columns it needs, compresses very well

Three things worth saying out loud when you make this choice.

"Postgres until proven otherwise." A well-run Postgres database handles JSON documents, full-text search, location data, and time-series data reasonably well all at once. Running one system you actually know how to operate beats running four you don't. Reaching for Cassandra at 200 requests a second is treated as a mistake, not a strength.

Using more than one kind of database at once is normal, but each one has a real cost. Every extra store is one more thing to back up, monitor, secure, and keep in sync with the others. Justify each one you add.

When you do use two stores, say clearly which one is the source of truth. For example: "Postgres holds the real data; Elasticsearch is a search index rebuilt from a stream of Postgres's own changes, and it might lag behind by about a second."

A one-line comparison of three popular wide-column and document stores. Cassandra has no single leader, spreads writes across many equal machines, and lets you tune correctness per request; it's hard to beat for write-heavy systems spread across regions. DynamoDB is a managed service shaped the same way, but it demands careful choice of the key you partition by. MongoDB has a leader-based design, is pleasant to build with day to day, and needs extra care once your data starts looking more like related tables than standalone documents.

Remember: start from the query you need to answer, not from a favourite database. "Postgres until proven otherwise" is a strong, defensible default.

Sign in to try this knowledge check.

Indexes: what they are and when they hurt

Think of a textbook with no index at the back. To find every page that mentions "mitosis," you'd have to read the whole book cover to cover. An index at the back tells you the exact page numbers, so you jump straight there instead. A database index works the same way: it's a separate structure that maps a column's values to where the matching rows actually live, so the database can jump straight to them instead of reading every single row.

sql
-- Without an index: sequential scan of 10M rows
SELECT * FROM tweets WHERE author_id = 42 ORDER BY created_at DESC LIMIT 20;

-- With this index: an index seek to author 42, then 20 rows read in order
CREATE INDEX idx_tweets_author_time ON tweets (author_id, created_at DESC);

When an index covers several columns, the order you list them in matters enormously. An index on columns (a, b, c) speeds up a query that filters on a alone, one that filters on a and b together, and one that filters on all three. This is called a left prefix, meaning it only helps when your query's filter starts matching from the leftmost column onward. It does not speed up a query that filters on b alone, skipping a. A rule worth remembering: put the columns you filter for an exact match first, and put the column you sort or filter by a range on last.

A covering index stores every column a query needs directly inside the index itself, so the database never has to go fetch the actual row separately. In Postgres this is written with INCLUDE (...). This turns two separate reads into one, and it's often the first thing to try when a specific query is running too slowly.

Indexes are not free. Here is what they cost you:

  • Every time you insert, update, or delete a row, every index on that table has to be updated too. A write-heavy table with eight indexes on it is really doing nine writes for every one you asked for.
  • They take up storage space and memory that the table's own frequently-used pages would otherwise use.
  • The database's query planner can sometimes choose a worse plan when its internal statistics are out of date.
  • Indexing a column with only a few possible values rarely helps. An index on a true-or-false column usually loses to simply scanning the whole table, because jumping around randomly through an index to fetch half the rows is slower than just reading them in order.

Indexes can silently fail to help in a few common situations: wrapping the column in a function, like WHERE lower(email) = ..., needs a special index built on that exact function; a search pattern starting with a wildcard, like LIKE '%foo', can't use a normal index either; neither can an implicit type conversion, or an OR condition spanning two different columns, which is often better rewritten as two queries combined with UNION.

Remember: a composite index on (a, b, c) only helps queries that filter starting from the left: a alone, a and b together, or all three. It cannot help a query that filters on b alone.

Sign in to try this knowledge check.

B-tree vs LSM-tree: why write-heavy stores are different

Picture two libraries handling returned books. Library A puts every returned book straight back onto its exact alphabetical shelf spot right away. That's slower per book, but any book is instantly findable afterward. Library B just drops every return onto a cart by the door, and once the cart is full, carries the whole thing to the shelves in one batch. That's much faster per return, but you might have to check both the cart and the shelf to find a specific book. Library A is how a B-tree works. Library B is how an LSM-tree works. This single difference explains almost everything about how a database behaves under reads versus writes.

A B-tree is used by Postgres, MySQL's InnoDB engine, and most relational databases. It's a balanced tree of fixed-size pages, and it updates those pages in place, directly where they already live.

  • Reading is predictable: roughly a handful of page reads no matter how big the table gets, and because the lowest level of the tree is kept sorted, scanning a range of values is cheap.
  • Writing means finding the right page, changing it, and writing it back. That's a random write to disk, plus an entry in a separate log kept purely to survive a crash. Over time, pages that keep splitting apart become fragmented.
  • Best suited to read-heavy or mixed workloads, range queries, and strong correctness on a single machine.

An LSM-tree, short for log-structured merge-tree, is used by Cassandra, RocksDB, LevelDB, HBase, and ScyllaDB. New writes land first in an in-memory table, get appended to a log on disk for safety, and are periodically flushed out into new, unchangeable, sorted files. A background process called compaction later merges those files back together.

  • Writing only ever appends data, never rewrites it in place, which is dramatically faster. This is exactly why LSM-based stores dominate write-heavy workloads.
  • Reading may have to check the in-memory table plus several of those sorted files on disk, a cost called read amplification. This is softened by keeping a Bloom filter per file, a small structure that can quickly say "definitely not in this file," and by the ongoing compaction process merging files together.
  • The costs: compaction uses real disk and CPU time in the background and can cause sudden slowdowns; a delete is really just a marker called a tombstone, and the space isn't actually freed until the next compaction; and duplicate copies of the same data can pile up temporarily before compaction cleans them up.
B-tree LSM-tree
How it writes Random, changes data in place Only ever appends
How much it can write Lower Much higher
How it reads One tree The in-memory table plus several files, helped by Bloom filters
How predictable a single read is Very predictable More variable
Range scans Excellent Good
Wasted space Fragmented pages Duplicate data until compaction runs
Background work Occasional cleanup (called vacuum) Compaction, which can cause sudden slowdowns
Deletes Changed in place Marked with a tombstone first

The one sentence worth memorising: B-trees make reads fast by paying a small cost on every write. LSM-trees make writes fast by paying that cost later, on reads and during background compaction.

Remember: a B-tree write updates data in place immediately. An LSM-tree write just appends, and cleans up later. That's why LSM-trees win on write-heavy workloads.

Sign in to try this knowledge check.

Transactions: ACID and isolation levels

Picture transferring 100 rupees from your account to a friend's. Two things have to happen: your balance drops by 100, and your friend's balance rises by 100. If the system crashes right after the first step but before the second, the money has simply vanished. A transaction is the database's promise that a group of changes like this happen together completely, or not at all.

ACID is the set of guarantees a transaction makes, and you should be able to defend each letter:

  • Atomicity means every statement in the transaction commits, or none of them do.
  • Consistency here means the transaction moves the database from one valid state to another, respecting whatever rules you've declared, like a column that must never be negative. This is a different "C" from the one in CAP, a topic covered in a later lesson; interviewers like to test whether you know that.
  • Isolation means transactions running at the same time don't see each other's unfinished work, at least to the degree the chosen isolation level actually promises.
  • Durability means once a transaction is confirmed, it survives a crash, thanks to a safety log, forcing data to disk, and often replication too.

Isolation levels decide which problems can still happen. Learn this table well:

Level Can you read another transaction's unfinished work? Can the same read return different values twice? Can new rows appear in a repeated range query? Cost
Read Uncommitted Yes Yes Yes Lowest
Read Committed (Postgres's default) No Yes Yes Low
Repeatable Read (MySQL's default; called "snapshot" in Postgres) No No Yes, except in Postgres, where it's also prevented Medium
Serializable No No No Highest, and can force retries under heavy contention

A few terms defined plainly. A dirty read means reading another transaction's work before it's even confirmed. A non-repeatable read means reading the same row twice in one transaction and getting two different answers. A phantom read means running the same range query twice and seeing new rows appear the second time. A lost update means two transactions each read a row, change it, and write it back, and one of those two changes silently disappears. Read Committed, Postgres's own default, does not protect you from a lost update.

The practical rule most teams follow: use Read Committed everywhere by default, and add explicit locking or an atomic write only in the small number of places where a lost update would actually matter.

sql
-- Lost update, the classic bug: two concurrent runs can both read 10 and both write 9.
SELECT seats FROM events WHERE id = 1;          -- 10
UPDATE events SET seats = 9 WHERE id = 1;

-- Fix 1 — pessimistic: take the row lock, then decide.
BEGIN;
SELECT seats FROM events WHERE id = 1 FOR UPDATE;
UPDATE events SET seats = seats - 1 WHERE id = 1;
COMMIT;

-- Fix 2 — optimistic: no lock; retry if someone else moved first.
UPDATE events SET seats = seats - 1, version = version + 1
WHERE id = 1 AND version = $expected_version AND seats > 0;
-- 0 rows affected → someone beat you → re-read and retry

-- Fix 3 — atomic and best when it applies: let the database do the arithmetic
-- and let a CHECK constraint enforce the invariant.
UPDATE events SET seats = seats - 1 WHERE id = 1 AND seats > 0;

Choosing between locking ahead of time (pessimistic) and checking afterward (optimistic) is a real trade-off worth naming. Locking ahead of time is right when many people are competing for the same thing at once, like booking the very last seat at a popular event. Checking afterward is right when competition is rare, like editing your own profile, because it never holds a lock and so scales better, at the cost of having to retry the occasional guess that turned out wrong.

MVCC (multi-version concurrency control) is the mechanism behind all of this in Postgres and MySQL. Instead of overwriting a row, a writer creates a new version of it, so readers never have to wait for writers, and writers never have to wait for readers. The cost is that old versions pile up and need periodic cleanup, called vacuuming, and a transaction left running for a long time can hold that cleanup back and let the table bloat.

Remember: Read Committed does not prevent a lost update. Two people reading the same row and both writing back is a real bug, and the fix is one single atomic UPDATE statement, not two separate application steps.

Sign in to try this knowledge check.

Quick recap

Choose by access pattern, not fashion. Postgres until proven otherwise.
Index = seek instead of scan. Composite = LEFT PREFIX only.
       equality columns first, range/sort column last. Covering index avoids the table read.
Index cost = write amplification + memory + planner risk. Low cardinality rarely helps.
B-tree  : in-place, random writes, great reads       → read-heavy, relational
LSM-tree: append-only, sequential writes, compaction → write-heavy, Cassandra/Rocks
ACID's C ≠ CAP's C.
Isolation: Read Committed (default) allows non-repeatable + phantom + LOST UPDATE.
Concurrency fixes: atomic UPDATE > optimistic version check > SELECT FOR UPDATE
MVCC: readers don't block writers; cost is VACUUM and long-transaction bloat.
PreviousCaching and CDNsNextReplication, Partitioning, and Sharding

Course progress

0%
0 of 177 modules complete

On this page

  • Picking a store from the access pattern
  • Indexes: what they are and when they hurt
  • B-tree vs LSM-tree: why write-heavy stores are different
  • Transactions: ACID and isolation levels
  • Quick recap