Which Database Should You Use? A Practical Guide to SQL, NoSQL, and More
If you have ever found yourself staring at a whiteboard, debating whether to choose PostgreSQL, MongoDB, or DynamoDB, you are not alone. The database ecosystem has exploded far beyond the traditional SQL monolith. While many guides tell you to “pick one,” the harsh reality of modern system design is that you rarely pick just one.
Welcome to the world of polyglot persistence: the art of using multiple database technologies within a single application to leverage their individual strengths.
Before we dive into the specifics, we need to address the underlying physics of distributed systems: The CAP Theorem. In a distributed system, you must choose two out of three: Consistency (every read gets the latest write), Availability (every request gets a response), and Partition Tolerance (the system continues despite network failures). Relational databases lean toward Consistency and Availability (CA), while most NoSQL systems lean toward Availability and Partition Tolerance (AP). This trade-off is the root of all your subsequent decisions.
Relational databases (PostgreSQL, MySQL) typically prefer CA: they guarantee strong consistency and availability within a single datacenter but may sacrifice partition tolerance. Distributed NoSQL systems (Cassandra, DynamoDB) often choose AP: they remain available and tolerant to network partitions but may return stale reads (eventual consistency).
Let’s cut through the noise. Here is your definitive, comprehensive guide to the nine major database paradigms, complete with anti-patterns, scaling strategies, and the operational realities nobody tells you about.
The Safe Default: Relational Databases (SQL)
The Titans: PostgreSQL, MySQL, SQLite
The Mechanism
Data is stored in structured tables with rows, columns, and strict schemas. They enforce relationships via foreign keys (for example, a post must belong to a valid user) and guarantee ACID (Atomicity, Consistency, Isolation, Durability) transactions.
The Strengths
- Query Flexibility: You can join tables, filter by any column, and run complex analytical aggregations.
- Data Integrity: The database actively rejects invalid data, ensuring correctness.
- Mature Tooling: ORMs, migration tools, and debugging suites are unparalleled.
The Bottlenecks (and how to fix them)
- Connection Limits: Every app server opening a connection will exhaust the database. Fix: Implement a connection pooler like PgBouncer.
- Row Locking: High-concurrency writes to the same row block each other. Fix: Optimistic locking or partitioning.
- Scaling: They are not infinitely scalable out-of-the-box. However, you can scale vertically, or horizontally using read replicas (offloading
SELECTqueries), indexing (B-trees for fast point lookups), and caching.
Honestly, most of the time. If your data has clear relationships (users, orders, inventory) and you need strict accuracy, this is your starting point.
When your schema changes daily (painful migrations), or you need massive horizontal scale beyond what read replicas and sharding can comfortably handle.
The Speed Demons: Key-Value Stores
The Titans: Redis, Amazon DynamoDB (in its core mode), Memcached
The Mechanism
A giant, distributed hashmap. You give it a key, and it returns a value (which is often a blob, JSON, or binary).
The Strengths
Blistering speed. Because the access pattern is a single, direct lookup, latency is measured in microseconds.
The Achilles’ Heel
Query flexibility is virtually zero. Want to find all users in a specific city? You cannot, unless you scan the entire dataset, which is a cardinal sin in production.
The Hotkey Problem (and Mitigation)
If a single key (for example, the profile of a celebrity) gets slammed with millions of requests, your partition will overload.
- Client-side caching: Store the hot key locally in the application memory.
- Row Cache: Use an in-memory cache (like Redis) in front of the key-value store to absorb the read load.
- Sharding Strategies: Use hash-based partitioning to distribute keys evenly, avoiding sequential patterns that cluster data.
Caching user sessions, real-time leaderboards, distributed locking, and storing user preferences.
If you need to query by anything other than the exact primary key, or if you need to run aggregations (such as SUM of sales).
The Write Warriors: Wide-Column Databases
The Titans: Apache Cassandra, ScyllaDB, Google Bigtable
The Mechanism
Data is stored in rows identified by a partition (row) key. Unlike relational databases, columns are not uniform across rows; you can add or “upsert” new columns to existing rows instantly.
The Strengths
- Massive Write Throughput: Because writes are append-only and immutable, they scale horizontally like a dream.
- Sparse Data: Perfect for storing data where different entities have wildly different attributes.
The Crucial Constraint
You must design your access pattern around your partition key. Retrieving data by the partition key is hyper-efficient; retrieving by a non-indexed column requires a full cluster scan and will take forever.
The Hot Partition Risk
Same as key-value; if you put all your IoT data for a single day into one row (for instance, partition_key = '2026-09-07'), you will overload that node. Solution: Design for a wide distribution, using composite keys like (region, timestamp) to ensure many rows.
Append-heavy data. Think IoT sensor readings, application event logs, time-series analytics, and user activity tracking where reads are less frequent than writes.
If you need strong consistency, secondary indexes, or ad-hoc analytical queries.
The Flexible Schemas: Document Databases
The Titans: MongoDB, Couchbase, Firestore
The Mechanism
Stores data as JSON/BSON documents. Each document can have a unique structure, eliminating the need for rigid schema migrations.
The Strengths
- Developer Agility: Your database structure evolves naturally with your code.
- Horizontal Sharding: Scales easily via sharding.
The Trade-off
Joins are virtually non-existent. To get related data, you must embed it (denormalize), leading to data duplication and complex update logic. Transaction support across multiple documents is limited compared to SQL.
Content management systems, user profiles, product catalogs with varying attributes, and rapid prototyping.
When your data is highly relational (for example, accounting ledgers, inventory management) and data integrity is non-negotiable.
The Analytical Engines: Time-Series and Search Databases
Time-Series Databases (InfluxDB, Prometheus, TimescaleDB)
These are purpose-built for data indexed by time. They offer specialized compression (reducing storage costs by 90% or more), downsampling, and retention policies.
- Use when: You have metrics, financial ticks, or monitoring data.
- Avoid when: You need to update old records frequently.
Search Engines (Elasticsearch, Meilisearch)
These are inverted-index powerhouses optimized for full-text search, relevance ranking (TF-IDF), and log analytics.
- Use when: You need “Google-like” search across text fields or observability dashboards.
- Avoid when: You are using it as a primary source of truth (it sacrifices consistency for availability and search speed).
Files and AI: Object Storage and Vector Databases
Object Storage (Amazon S3, Google Cloud Storage)
The Mechanism: A flat namespace for files (images, videos, backups, Parquet files). No tables, no schemas, just PUT, GET, and DELETE.
Never scan. Always retrieve by the exact key. If you need to list thousands of objects, especially in huge buckets, you will face massive latency.
Use when: Storing media assets, data lake files, or application backups. It is incredibly cheap at scale.
Vector Databases (Pinecone, Milvus, pgvector)
The Mechanism: Stores high-dimensional embeddings (numeric arrays generated by ML models). It uses algorithms like HNSW (Hierarchical Navigable Small World) to find “nearest neighbors.”
The Use Case: Semantic search, RAG (Retrieval-Augmented Generation), and recommendation systems. You feed it a query vector (for instance, “Find me funny cat videos”), and it returns the closest matching vectors.
The Network Navigators: Graph Databases
The Titans: Neo4j, Amazon Neptune
The Mechanism
Data is stored as Nodes (entities) and Edges (relationships). Traversing relationships (for example, “friends of friends of friends”) is native and extremely fast.
The Warning
Relational databases can handle basic graphs. However, if you try to go 3 to 5 hops deep in a SQL WITH RECURSIVE query, performance will plummet exponentially. Graph databases excel at multi-hop traversals.
Social networks (finding degrees of separation), fraud detection (circle-of-friends analysis), and supply chain mapping.
When your relationship queries are shallow (1–2 hops) or infrequent. The operational overhead of Neo4j is usually not worth it for basic relationships.
The Ultimate Decision Matrix
| Database Type | Use It When | Avoid It When |
|---|---|---|
| Relational (SQL) | Data is structured and requires ACID integrity. (Default choice). | Schema changes hourly, or you need infinite horizontal scaling. |
| Key-Value | You need sub-millisecond latency for simple key lookups. | You need to query by attributes other than the key. |
| Wide-Column | You have massive write volumes and predictable partition-key queries. | You need ad-hoc queries, joins, or strong consistency. |
| Document | Your data is semi-structured and changes frequently. | You have highly relational data requiring complex cross-collection transactions. |
| Time-Series | You are ingesting continuous metrics or ticks by time. | You need to update or delete individual records frequently. |
| Search Engine | You need full-text search, fuzzy matching, or log aggregation. | You are relying on it as the system of record. |
| Object Storage | Your data is a file (image, video, backup). | You need to retrieve data by querying metadata without an index. |
| Vector | You are building AI/RAG applications requiring similarity search. | You don’t need semantic or similarity-based retrieval. |
| Graph | Relationships are the core of your product. | You only do 1-hop relational lookups. |
Scaling Strategies: The Operational Reality
Knowing which database to pick is half the battle. Here is how you make them survive production loads.
Indexing
The fastest way to speed up a relational DB. Always index your WHERE and JOIN columns.
Caching
Implement a caching layer (Redis/Memcached) to serve repeated reads without hitting the primary database. This is the primary defense against the “hotkey” problem.
Read Replicas
Offload your reporting and analytics queries to read-only replicas, preserving the primary node’s compute for writes.
Sharding
When vertical scaling (buying a bigger machine) hits a wall, horizontal scaling (sharding) distributes data across machines. Ensure your shard key evenly distributes traffic.
Connection Pooling
Never let your app servers open unlimited connections to the DB. Pool them to prevent resource exhaustion.
The Cost of Convenience
Managed services (AWS RDS, DynamoDB, S3) are fantastic for reducing operational overhead. However:
- DynamoDB charges per read/write unit; high throughput can become shockingly expensive.
- Cassandra/Scylla (self-hosted) runs on commodity hardware, making it much cheaper at massive scale than managed relational DBs.
- S3 is dirt cheap for storage but charges per API request. If you are listing huge buckets, those
ListObjectsAPI calls add up quickly.
Rule of thumb: Start with managed services to move fast. As you scale, evaluate the cost of moving to self-hosted solutions if your engineering team can handle the maintenance (backups, patching, monitoring).
The Final Verdict
Do not overthink the initial choice. Start with a relational database (PostgreSQL). It handles 95% of startup workloads beautifully.
As your traffic grows, adopt polyglot persistence:
- Add Redis for sessions and caching.
- Add S3 for file storage.
- If your text search becomes heavy, migrate search to Elasticsearch.
- If your writes explode, channel event logs into Cassandra or Kafka + S3.
Technology is a toolbox, not a religion. The core principle remains: Relational is your anchor. Specialized databases are your accelerators. Use them wisely, mitigate your hot keys, design your primary access patterns, and you will build systems that scale gracefully far beyond your initial expectations.
