0% completed
SQL vs. NoSQL
On This Page
Relational Databases
NoSQL Is Five Different Things
The Schema Does Not Disappear
Joins or Duplication
Transactions
How Each One Grows
How to Choose
The Real Answer Is Usually Both
Key Takeaways
Every application stores its data somewhere. Those stores fall into two families, called SQL and NoSQL.
SQL is the name of a query language, but people use it as the name of a whole family. The proper name for that family is relational databases. MySQL, PostgreSQL, Oracle, and SQL Server are the common ones.
NoSQL is a loose label for databases that do not use the relational model. It is not one product and not one design. The five families below are the ones you will meet most often, and they have less in common with each other than people expect. Others exist, such as search engines and time-series stores.
Relational Databases
A relational database keeps data in tables. A table has named columns with fixed types, and each record is a row.
You define the table before you store anything. That definition is the schema. It lists the columns, their types, and which values are required. The database refuses any row that does not match.
Tables point at each other with a foreign key, a column holding the key of a row in another table. An orders table holds a user_id, and that value must exist in the users table. The database checks this on every write.
You read the data with SQL, short for Structured Query Language. You say what you want, not how to find it. One query can read several tables, filter, group, and sort.
NoSQL Is Five Different Things
The word NoSQL covers five separate designs. Picking "NoSQL" is not a decision. Picking one of these five is.
Key-value stores hold a value under a key. You set a value by its key and get it back by its key. That is almost the whole interface, which is why it is fast. The simplest stores, such as Memcached, never look inside the value. The common ones go further. Redis values are typed structures whose fields you can read one at a time, and Amazon DynamoDB can index and filter on the attributes inside an item.
Document stores hold each record as a document, usually JSON. A document can hold nested fields, so one order can contain its own list of items. You can search on fields inside the document and build indexes on them. MongoDB is the common one.
Wide-column stores group rows under a partition key and store each row as a sparse set of columns, so a column that is not set takes no space in that row. Cassandra still declares the columns and their types in the table definition, and a new one is added with ALTER TABLE. They are built to take very high write rates across many machines. You design the tables around the exact queries you will run. Apache Cassandra is the common one.
Graph databases hold nodes and the edges between them. A query walks the edges: the friends of my friends who live in this city. In a relational database, every step of that walk is another join. Neo4j is the common one.
Vector stores hold embeddings, which are fixed-length arrays of numbers that stand for the meaning of a piece of text, an image, or audio. The query is different from every store above: instead of asking for an exact match, you hand it a vector and ask for the nearest ones, measured by cosine similarity or dot product. That is what makes semantic search and retrieval-augmented generation possible, where a question finds passages that mean the same thing rather than passages containing the same words. Pinecone, Weaviate, Qdrant and Milvus are the dedicated ones.
Two details make this a real design decision rather than a product choice. The index is approximate, usually HNSW or IVF, so it trades a little recall for a large gain in speed, and how much recall you are willing to lose is a number worth stating out loud. And it is often not a separate database at all: pgvector gives Postgres the same capability, and several stores above have added vector indexes. "Do I need a vector database, or a vector index on the database I already run" is a reasonable answer in an interview, and usually the better one at small scale.
The Schema Does Not Disappear
A relational database enforces the schema itself. A row with a missing column or a wrong type is rejected. You change the schema with a migration, a statement such as ALTER TABLE. On a large table this needs planning, because it can lock the table.
Most NoSQL stores accept whatever you send. Two records in the same collection can hold different fields. This is often called schema-less, and that word is misleading.
The schema still exists. If some records have a phone field and some do not, every reader must handle both cases. The schema moved out of the database and into your application, where nothing checks it for you.
Teams get the check back by validating data before they write it, in their own code or with an ORM. An ORM is a library that maps stored records to objects in your programming language.
The two families overlap here. PostgreSQL and MySQL can store a JSON column inside a normal table, and PostgreSQL can index fields inside that JSON. So you can keep fixed columns for the data you understand and one flexible column for the rest. MongoDB can go the other way and enforce a schema.
Joins or Duplication
Relational design normally stores each fact once. A user's name lives in the users table only, and orders point at that user with a foreign key. Storing data this way is called normalization. Changing the name is one write.
Reading an order together with the user's name then needs a join, which combines rows from two tables on a matching column.
Most NoSQL stores do not join, and the ones that can are limited. MongoDB joins collections with the $lookup stage, but the cost grows quickly and it is restricted once the data is sharded. So the usual design is to store together what you read together, and the order document holds a copy of the user's name inside it. The read is one fast lookup. The cost is that the name now exists in many places, so changing it means updating every copy. Storing data this way is called denormalization.
You are choosing whether to pay on reads or on writes. Normalization vs Denormalization works through the trade in detail.
Transactions
A transaction groups several changes so that all of them happen or none of them do. Moving money between two accounts is the usual example.
Relational databases follow ACID: atomicity, consistency, isolation, and durability. Together these mean a committed transaction is complete, correct, and not lost.
Many distributed NoSQL stores were built to stay available instead. They describe themselves with BASE: basically available, soft state, and eventual consistency. A write reaches one machine first, so a read straight after it can return the old value.
This no longer separates the two families. MongoDB and DynamoDB both support transactions across several records. Google Spanner and CockroachDB are relational, distributed, and still give you ACID. ACID vs BASE and Strong vs Eventual Consistency cover this properly.
How Each One Grows
A relational database usually grows in three steps.
First you buy a bigger machine: more CPU, more memory, a faster disk. Nothing in your code changes.
Then you add read replicas, which are copies of the database that answer read queries. Writes still go to one machine.
Then, when one machine can no longer take the writes, you split the data across machines. A plain MySQL server does not do this for you. You add a layer such as Vitess for MySQL or Citus for PostgreSQL, or you move to a distributed relational database such as Spanner.
Many NoSQL stores do that third step from the first day. Cassandra and DynamoDB spread data across machines by key. With Cassandra you add a node and the cluster moves data onto it. DynamoDB is managed, so you raise its capacity instead, and the service splits the partitions for you. You pay for that: work spanning many records is limited.
Data Partitioning explains how the split itself works.
How to Choose
Start with the questions your system has to answer, not with the product name.
Choose a relational database when:
- The data has clear relationships and you will query across them: orders, customers, products, invoices.
- Money or stock counts are involved, and a wrong number is not acceptable.
- You do not yet know every query. SQL lets you ask new ones later.
- People will run reports on the data.
Choose a NoSQL store when:
- The access pattern is one fixed lookup by key, such as a session or a profile by user id.
- The write rate is higher than one machine can take, and it will keep growing.
- The records have different shapes, and those shapes keep changing.
- The question is about the relationships themselves, several steps deep. That is a graph database.
- The question is "what is closest in meaning to this", over embeddings rather than exact values. That is a vector store, or a vector index on a database you already run.
The Real Answer Is Usually Both
Large systems rarely pick one store. An online shop can keep orders and payments in PostgreSQL, sessions in Redis, and event logs in Cassandra. Using several stores, each for the job it is good at, is called polyglot persistence.
Every extra store is another system to run, and copies of the same data have to be kept in step. Add a second store when the first one is clearly wrong for one job, and not before.
Key Takeaways
- Relational databases store rows in tables with a fixed schema, link them with foreign keys, and are read with SQL.
- NoSQL is not one thing. It is key-value, document, wide-column, graph, and vector stores, and they solve different problems.
- The schema does not disappear in a store that accepts any shape, such as a document or key-value store. It moves into your application, where the database no longer checks it. Other stores keep the check: Cassandra declares a type for every column, and MongoDB can validate documents against a schema.
- Relational design normalizes and joins. NoSQL design stores data together and duplicates it: faster to read, harder to update.
- ACID and BASE no longer split the two families. Several NoSQL stores support transactions, and several relational stores are distributed.
- Relational growth is usually bigger machine, then read replicas, then a sharding layer such as Vitess. Many NoSQL stores spread across machines from the start.
- Choose relational for relationships, correctness, and unknown queries. Choose NoSQL for one fixed access pattern, very high write rates, or changing record shapes. Most large systems use both.
In an interview, "I would use NoSQL" is not an answer, because NoSQL is five different designs. Name the store and the reason: a document store because the records vary, or a wide-column store because one machine cannot take the writes. The SQL vs. NoSQL comparison lesson puts the two families side by side.
chosunone
· 8 months ago
Postgres has good support for JSON columns, including even creating indexes on the fields in the JSON column, so you can have the benefit of being able to progressively move from a more dynamic schema to a more strict one.
John O' Grady
· 9 months ago
Can you explain ORM? I don't think that term has come up in this course already.
Reading Progress
0%
On This Page
Relational Databases
NoSQL Is Five Different Things
The Schema Does Not Disappear
Joins or Duplication
Transactions
How Each One Grows
How to Choose
The Real Answer Is Usually Both
Key Takeaways