SQL vs NoSQL: Choosing the Right Database

A comprehensive comparison of relational and non-relational databases, their trade-offs, and decision frameworks for system design.

Choosing between SQL and NoSQL is one of the most fundamental architectural decisions. This guide helps you make an informed choice based on your specific requirements.

Quick Comparison

Aspect SQL (Relational) NoSQL (Non-Relational)
Data Model Tables, rows, columns Documents, key-value, wide-column, graph
Schema Fixed, enforced Flexible, schema-on-read
Query Language SQL (standardized) Varies by database
Transactions ACID (strong) BASE (eventual)
Scaling Vertical (primarily) Horizontal (native)
Joins Native support Limited/denormalized
Consistency Strong Eventual (tunable)

SQL Databases

When to Choose SQL

  1. Complex relationships: Foreign keys, joins, many-to-many
  2. ACID transactions required: Financial, inventory, booking systems
  3. Structured, stable schema: Well-defined entities that don’t change often
  4. Ad-hoc queries: Need flexible querying without knowing access patterns upfront
  5. Mature ecosystem: Tooling, ORMs, migration tools, expertise
Database Best For Notable Features
PostgreSQL General purpose, complex queries JSONB, extensions, window functions
MySQL Web applications, read-heavy Simple, fast, wide adoption
SQL Server Enterprise, .NET ecosystem T-SQL, integration services
CockroachDB Distributed SQL Horizontal scaling, strong consistency
TiDB HTAP (hybrid transactional/analytical) MySQL compatible, distributed

Schema Design Example

-- Normalized schema for e-commerce
CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email VARCHAR(255) UNIQUE NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE orders (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID REFERENCES users(id),
    status VARCHAR(50) NOT NULL DEFAULT 'pending',
    total_cents INTEGER NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE order_items (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    order_id UUID REFERENCES orders(id),
    product_id UUID NOT NULL,
    quantity INTEGER NOT NULL,
    price_cents INTEGER NOT NULL
);

-- Indexes for common queries
CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_orders_status_created ON orders(status, created_at DESC);

NoSQL Databases

Types of NoSQL

Document Databases (MongoDB, Couchbase)

  • Store JSON-like documents
  • Flexible schema, nested data
  • Good for: Content management, catalogs, user profiles

Key-Value Stores (Redis, DynamoDB, Riak)

  • Simple key → value mapping
  • Extremely fast reads/writes
  • Good for: Caching, sessions, shopping carts

Wide-Column Stores (Cassandra, HBase, ScyllaDB)

  • Column families, sparse columns
  • Time-series, high write throughput
  • Good for: Logging, metrics, sensor data

Graph Databases (Neo4j, Amazon Neptune, ArangoDB)

  • Nodes and relationships
  • Traversals, recommendations
  • Good for: Social networks, fraud detection, knowledge graphs

When to Choose NoSQL

  1. Massive scale: Petabytes, millions of writes/second
  2. Flexible schema: Rapidly changing data structures
  3. Specific access patterns: Known query patterns, no ad-hoc queries
  4. High availability: AP systems for global applications
  5. Specialized workloads: Time-series, graphs, key-value

NoSQL Data Modeling

// MongoDB: Embedded vs Referenced
// Embedded (one-to-few, read together)
{
  _id: ObjectId("..."),
  title: "System Design Notes",
  author: { name: "John", email: "john@example.com" },
  sections: [
    { title: "CAP Theorem", content: "...", order: 1 },
    { title: "Consensus", content: "...", order: 2 }
  ],
  tags: ["distributed-systems", "architecture"],
  createdAt: ISODate("2024-01-15")
}

// Referenced (one-to-many, independent lifecycle)
{
  _id: ObjectId("..."),
  title: "System Design Notes",
  authorId: ObjectId("..."),  // Reference to users collection
  sectionIds: [ObjectId("..."), ObjectId("...")],  // Array of refs
  tags: ["distributed-systems", "architecture"]
}

Decision Framework

START: What's your data like?
├── Highly relational, complex joins?
│   └── YES → SQL (PostgreSQL)
├── Need ACID transactions?
│   └── YES → SQL (PostgreSQL, CockroachDB)
├── Massive scale, simple access patterns?
│   └── YES → NoSQL (Cassandra, DynamoDB)
├── Flexible schema, rapid iteration?
│   └── YES → NoSQL (MongoDB)
├── Graph relationships, traversals?
│   └── YES → Graph DB (Neo4j)
├── Key-value, caching, sessions?
│   └── YES → Redis, DynamoDB
└── Time-series, metrics, logs?
    └── YES → Wide-column (TimescaleDB, InfluxDB)

Hybrid Approaches

Many modern systems use polyglot persistence:

┌─────────────────────────────────────────────────┐
│                  Application                     │
└──────────┬──────────────┬───────────┬───────────┘
           │              │           │
    ┌──────▼──────┐ ┌─────▼────┐ ┌────▼────┐
    │ PostgreSQL  │ │  Redis   │ │Elastic  │
    │ (Orders,    │ │ (Cache,  │ │Search   │
    │  Users,     │ │  Sessions)│ │(Logs,   │
    │  Payments)  │ │          │ │  Docs)  │
    └─────────────┘ └──────────┘ └─────────┘

NewSQL: Best of Both Worlds

NewSQL databases provide horizontal scaling with ACID:

  • CockroachDB: PostgreSQL-compatible, geo-distributed
  • TiDB: MySQL-compatible, HTAP
  • Google Spanner: Global consistency with TrueTime
  • YugabyteDB: PostgreSQL-compatible, multi-cloud
-- CockroachDB: Globally distributed, strong consistency
CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email STRING UNIQUE NOT NULL,
    region STRING NOT NULL
) 
WITH (replication_zone = 'global');

Checklist for Database Selection

  • What are the access patterns? (Known vs ad-hoc)
  • What are the consistency requirements? (Strong vs eventual)
  • What is the scale? (Current and projected)
  • What is the team expertise? (SQL vs NoSQL experience)
  • What are the operational constraints? (Managed vs self-hosted)
  • What are the compliance requirements? (ACID, audit trails)
  • What is the data lifecycle? (Retention, archival, GDPR)

Further Reading

Related Notes