Skip to content
LowLevelDesign Mastery

Choosing the Right Database

The right tool for the right job

Choosing the right database is one of the most critical decisions in system design. The wrong choice can lead to performance problems, scaling issues, and development headaches.

Consequences of database choice: the wrong choice brings poor performance and high cost, the right one easy scaling and simple queries
Database choice by data structure: structured to SQL, semi-structured to document DB, key-value pairs to KV store, relationships to graph DB

Questions to Ask:

  • Is your data structured (tables) or unstructured (documents)?
  • Do you have fixed relationships or flexible structures?
  • Do you need to store nested/hierarchical data?

Database choice by query pattern: complex JOINs and aggregations to SQL, simple key lookups to NoSQL, relationship traversals to graph DB

Questions to Ask:

  • Do you need complex JOINs or simple lookups?
  • Are queries mostly by key or by complex conditions?
  • Do you need to traverse relationships?

Database choice by scale: under 1M records either works, up to 1B needs SQL replicas or NoSQL, beyond 1B records calls for NoSQL

Questions to Ask:

  • How many records do you expect?
  • What’s your expected QPS (queries per second)?
  • Do you need horizontal scaling?

Database choice by consistency: strong ACID consistency for financial data points to SQL, eventual consistency for social media to NoSQL

Questions to Ask:

  • Do you need ACID transactions?
  • Can you tolerate eventual consistency?
  • Is data accuracy critical or is speed more important?

Use CaseData StructureQuery PatternScaleConsistencyRecommended
E-commerceStructuredComplex JOINsMediumStrongSQL (PostgreSQL)
Social MediaSemi-structuredSimple lookupsLargeEventualDocument DB (MongoDB)
CachingSimpleKey lookupLargeEventualKey-Value (Redis)
Social NetworkRelationshipsGraph queriesLargeEventualGraph DB (Neo4j)
Time-SeriesStructuredColumn queriesLargeEventualColumn-Family (Cassandra)
FinancialStructuredComplex queriesMediumStrongSQL (PostgreSQL)
Content ManagementSemi-structuredDocument queriesMediumEventualDocument DB (MongoDB)
Session StorageSimpleKey lookupLargeEventualKey-Value (Redis)

Understanding how major companies choose databases helps illustrate the decision process:

The Challenge: E-commerce platforms have diverse data needs: structured orders, flexible products, fast sessions, complex search.

The Solution: Amazon uses multiple databases:

  • PostgreSQL: User accounts, orders, payments (ACID transactions, complex queries)
  • DynamoDB: Product catalog, inventory (high scale, simple queries)
  • Elasticsearch: Product search (full-text search, faceted search)
  • Redis: Shopping cart, sessions (fast lookups, temporary data)

Why Multiple Databases?

  • Different data has different requirements
  • Right tool for each job
  • Optimized performance

Example: User shopping flow:

  1. Login → PostgreSQL (user account)
  2. Browse products → DynamoDB (product catalog)
  3. Search → Elasticsearch (product search)
  4. Add to cart → Redis (shopping cart)
  5. Checkout → PostgreSQL (order, payment)

Impact: Optimized for each use case. Fast performance. Handles millions of users.

The Challenge: Social media platforms need flexible content (posts vary) and relationship queries (friends, followers).

The Solution: Facebook uses hybrid approach:

  • MySQL: User accounts, core data (ACID transactions)
  • MongoDB: Posts, comments, content (flexible schema)
  • Neo4j: Friend relationships, recommendations (graph traversals)
  • Cassandra: Messages, notifications (time-series, high scale)

Why Hybrid?

  • Posts have flexible structure → Document DB
  • Friend relationships → Graph DB
  • Messages over time → Column-Family DB

Impact: Handles billions of users. Fast relationship queries. Flexible content storage.

The Challenge: Financial platforms need strong consistency, complex queries, and ACID transactions.

The Solution: Banks use SQL databases:

  • PostgreSQL/Oracle: All financial data (accounts, transactions, balances)
  • Why SQL? ACID transactions, complex queries, strong consistency

Example: Money transfer:

  • Begin transaction
  • Debit account A
  • Credit account B
  • Commit transaction
  • All or nothing (atomicity)

Impact: Zero data loss. Strong consistency. Critical for financial systems.

The Challenge: Content platforms store articles, blog posts, user-generated content with varying structures.

The Solution: Medium uses MongoDB:

  • MongoDB: Articles, posts, user profiles (flexible schema)
  • Why Document DB? Content varies, nested data, no JOINs needed

Example: Article document:

{
"id": 123,
"title": "Article",
"author": {...},
"content": "...",
"tags": [...],
"comments": [...]
}

Impact: Flexible content storage. Fast reads. Scales horizontally.



E-commerce example: structured data, complex queries and ACID checkout requirements lead to a PostgreSQL SQL database

Why SQL?

  • Structured product/order/user data
  • Need complex queries (reports, analytics)
  • ACID transactions for checkout
  • Relationships between entities

Social media feed example: flexible schema, simple queries and high read scale lead to storing posts in MongoDB as documents

Why Document DB?

  • Flexible post structure (text, images, videos)
  • Simple queries (get user’s posts)
  • Need to scale horizontally
  • Fast reads more important than complex queries

Recommendation engine example: user and product relationship traversals lead to a Neo4j graph database with users as nodes

Why Graph DB?

  • Complex relationships (users, products, purchases)
  • Need to traverse relationships
  • “Find similar users” queries
  • Relationship queries are primary use case

Polyglot persistence means using multiple database types in the same system. Different parts use different databases optimized for their needs.

Polyglot persistence: one system uses PostgreSQL for orders and accounts, MongoDB for profiles and posts, and Redis for sessions and cache

Example: E-commerce platform

  • PostgreSQL: Orders, payments, inventory (structured, ACID)
  • MongoDB: Product catalogs, reviews (flexible schema)
  • Redis: Shopping cart, sessions, cache (fast lookups)

How database choice affects your class design:

Database Abstraction
from abc import ABC, abstractmethod
from typing import Optional
class UserRepository(ABC):
"""Abstract repository - database agnostic"""
@abstractmethod
def find_by_id(self, user_id: int) -> Optional['User']:
pass
@abstractmethod
def save(self, user: 'User') -> 'User':
pass
class SQLUserRepository(UserRepository):
"""SQL implementation"""
def __init__(self, db_connection):
self.db = db_connection
def find_by_id(self, user_id: int) -> Optional['User']:
# SQL query
cursor = self.db.execute("SELECT * FROM users WHERE id = ?", (user_id,))
row = cursor.fetchone()
return User.from_row(row) if row else None
def save(self, user: 'User') -> 'User':
# SQL insert/update
self.db.execute(
"INSERT INTO users (id, name, email) VALUES (?, ?, ?)",
(user.id, user.name, user.email)
)
return user
class MongoDBUserRepository(UserRepository):
"""MongoDB implementation"""
def __init__(self, mongo_collection):
self.collection = mongo_collection
def find_by_id(self, user_id: int) -> Optional['User']:
# MongoDB query
doc = self.collection.find_one({"_id": user_id})
return User.from_document(doc) if doc else None
def save(self, user: 'User') -> 'User':
# MongoDB insert/update
self.collection.replace_one(
{"_id": user.id},
user.to_document(),
upsert=True
)
return user


Now that you understand database selection, let’s dive deep into indexing strategies to optimize database performance:

Next up: Database Indexing Strategies — Learn about B-trees, LSM trees, and inverted indexes for designing searchable entities.