Databases · lesson 1 of 6
Intermediate
2Advanced
4Also part of Databases
12- + Schema Design from SQL
- + Indexing Strategy: When an Index Actually Helps from PostgreSQL
- + Composite Indexes: The Filesort a Single-Column Index Can't Avoid from MySQL
- + Clustered vs Nonclustered: When an Index Makes a Query Slower from SQL Server
- + A Real Deadlock, and Why Lock Order Fixed It from PostgreSQL
- + Isolation Levels: The Same Transaction Reading Two Different Values from MySQL
- + A Real Dirty Read: Seeing a Value That Never Actually Existed from SQL Server
- + Replication: A Second Server, and the read_only Gap Nobody Mentions from MySQL
- + Killing the Primary and Measuring the Real Failover Time from MongoDB
- + Point-in-Time Recovery: Undoing a Bad DELETE That Already Committed from PostgreSQL
- + Backup and Recovery: What a Restore Actually Gives Back from MySQL
- + Quorum Consistency: When a Read Is Guaranteed to See the Latest Write from System Design
Choosing a Database: A Decision Framework With Real Numbers
"It depends" is true and useless. A weighted scoring framework — consistency, query flexibility, write latency, schema flexibility — run against three real scenarios to three different, honest winners.
By SkillByExample · Updated
“It depends” is true and useless. What makes it useful is naming what it depends on, putting
a number on it, and running the same scoresheet against a real scenario instead of a generic
one — the same approach the cloud track uses to choose between AWS, Azure, and GCP, applied
here to choosing between database engines.
Four factors, scored once
# choose_database.py
def recommend(name, weights, scores):
engines = ("PostgreSQL", "MongoDB", "Redis")
totals = {e: sum(w * scores[f][e] for f, w in weights.items()) for e in engines}
ranked = sorted(totals.items(), key=lambda kv: -kv[1])
print(name)
for engine, total in ranked:
print(f" {engine:<11}{total:5.2f}")
print(f" -> recommend {ranked[0][0]}\n")
SCORES = {
"consistency": {"PostgreSQL": 9, "MongoDB": 7, "Redis": 3},
"query_flexibility": {"PostgreSQL": 9, "MongoDB": 7, "Redis": 2},
"write_latency": {"PostgreSQL": 6, "MongoDB": 7, "Redis": 10},
"schema_flexibility": {"PostgreSQL": 6, "MongoDB": 9, "Redis": 7},
}
Each engine gets one 0-10 score per factor, scored once, reused across every scenario — only the weights change per scenario, because the weights are where the actual judgment about a specific workload lives.
Three scenarios, three honest winners
recommend(
"E-commerce order system",
{"consistency": 0.45, "query_flexibility": 0.25, "write_latency": 0.10, "schema_flexibility": 0.20},
SCORES,
)
recommend(
"Real-time game leaderboard",
{"consistency": 0.10, "query_flexibility": 0.05, "write_latency": 0.65, "schema_flexibility": 0.20},
SCORES,
)
recommend(
"Content catalog, evolving schema",
{"consistency": 0.10, "query_flexibility": 0.30, "write_latency": 0.10, "schema_flexibility": 0.50},
SCORES,
)
$ python choose_database.py
E-commerce order system
PostgreSQL 8.10
MongoDB 7.40
Redis 4.25
-> recommend PostgreSQL
Real-time game leaderboard
Redis 8.30
MongoDB 7.40
PostgreSQL 6.45
-> recommend Redis
Content catalog, evolving schema
MongoDB 8.00
PostgreSQL 7.20
Redis 5.40
-> recommend MongoDB
Same three engines, same four scores per engine — three different winners, each one following directly from what that scenario actually weighted.
Reading the leaderboard result closely
Redis loses badly on 3 of 4 factors in every single scenario — its query_flexibility score
of 2 is the lowest number in the whole table. It still wins the leaderboard scenario outright
because that scenario puts 0.65 of the total weight — nearly two-thirds — on
write_latency, where Redis scores a 10 against Postgres’s 6. The framework doesn’t
average a database’s weaknesses away; a large enough weight on one real strength is enough to
win on its own.
Reading the content-catalog result closely
This is the one worth sitting with, because a common assumption — “flexible schema always
means MongoDB” — turns out to be conditional on how much weight schema flexibility actually
gets. At 0.50, MongoDB’s schema_flexibility score of 9 (against PostgreSQL’s 6, since
JSONB adds flexibility to a fundamentally table-shaped model rather than replacing it) is
enough to overcome PostgreSQL’s higher scores on the other three factors combined. Drop that
weight to 0.20 — the same weight used in the e-commerce scenario — and PostgreSQL wins this
scenario too, because the deciding factor no longer decides.
Why this beats “it depends”
None of the three engines’ own documentation can honestly run this comparison — each project’s docs are written to make that project look good, not to fairly score a competitor. That’s the gap this framework fills: the same four factors, scored once, reused against whatever weights actually describe your workload.
Practice
1. Add a fourth engine, MySQL, with its own scores, and re-run the e-commerce scenario.
SCORES["consistency"]["MySQL"] = 8
SCORES["query_flexibility"]["MySQL"] = 8
SCORES["write_latency"]["MySQL"] = 7
SCORES["schema_flexibility"]["MySQL"] = 5
def recommend(name, weights, scores):
engines = ("PostgreSQL", "MongoDB", "Redis", "MySQL")
totals = {e: sum(w * scores[f][e] for f, w in weights.items()) for e in engines}
ranked = sorted(totals.items(), key=lambda kv: -kv[1])
print(name)
for engine, total in ranked:
print(f" {engine:<11}{total:5.2f}")
E-commerce order system
PostgreSQL 8.10
MongoDB 7.40
MySQL 7.30
Redis 4.25
recommend() was written generically over the engine dict, so adding a fourth engine needed
no change to the scoring logic — only one more key in SCORES and the engines tuple.
2. Add a fifth factor, "operational maturity," and give it real weight in the e-commerce scenario.
SCORES["operational_maturity"] = {"PostgreSQL": 9, "MongoDB": 7, "Redis": 8}
weights = {"consistency": 0.35, "query_flexibility": 0.20, "write_latency": 0.10,
"schema_flexibility": 0.15, "operational_maturity": 0.20}
Re-running with this fifth factor keeps PostgreSQL on top for this scenario — its already strong scores are reinforced rather than contradicted — but the exact margin changes, which is the point of scoring instead of guessing: you can see how sensitive a recommendation is to a factor you just added.
3. Set every weight equal (0.25 each) for all three scenarios and compare.
Equal weights erase the scenario-specific reasoning entirely — the leaderboard scenario and the e-commerce scenario would get scored identically, which throws away exactly the judgment call (“what does this workload actually need”) that makes the framework useful in the first place.
4. Score your own current project's database choice against these four factors.
Write down honest 0-10 scores for the engines you’re actually choosing between, and weights that reflect what genuinely matters for that project — not what you’d like to matter. A result that disagrees with your gut is worth investigating before you commit to it.
Next: transactions across engines — which of these can actually roll back a partial failure, and which can’t.