Skalbar datalagring: SQL eller NoSQL
Välj mellan relationsdatabaser, key-value-databaser, dokumentdatabaser och wide-column-databaser utifrån åtkomstmönster, konsekvenskrav och skalbarhetsbehov.
Skalbar datalagring: SQL eller NoSQL är en gratis lektion i Förberedelse inför kodningsintervjuer på CoddyKit. Detta är lektion 2 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Förberedelse inför kodningsintervjuer, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Förberedelse inför kodningsintervjuer innehåller totalt 4 lektioner.
Valet av lagring är en avvägning
Att välja datalager är ett av de mest avgörande besluten inom systemdesign. Ingen databas är universellt bäst — varje typ är optimerad för olika åtkomstmönster, konsistensgarantier och skalningsegenskaper. Om ni väljer fel i produktion kan det leda till månader av mödosamt migreringsarbete.
I intervjuer undersöker intervjuarna om ni förstår de grundläggande skillnaderna och kan matcha en lagringsmotor mot kraven i ett problem. Frågan är aldrig ”vilken är bättre?” utan ”vilken är bättre för just den här arbetsbelastningen?” Motivera alltid ert val med specifika krav.
# Storage decision matrix summary
factors = [
'Data structure (tabular, documents, key-value, graph, time-series)',
'Read vs write ratio (read-heavy, write-heavy, balanced)',
'Query patterns (point lookups, range scans, aggregations, joins)',
'Consistency requirements (ACID vs eventual consistency)',
'Scale requirements (single node, sharding, global distribution)',
'Latency requirements (milliseconds vs microseconds)',
'Team familiarity and operational complexity',
]
print('Key factors for storage selection:')
for f in factors:
print(f' - {f}')Relationsdatabaser (SQL): styrkor
Relationsdatabaser (PostgreSQL, MySQL, SQLite) lagrar data i tabeller med fasta scheman och stöder ACID-transaktioner — atomäritet, konsistens, isolering och varaktighet. De är utmärkta för komplexa frågor med joins, aggregeringar och filter, vilket gör dem idealiska för strukturerade data med väldefinierade relationer.
Viktiga styrkor: komplexa frågor över flera tabeller via SQL, främmande nycklar för dataintegritet, kraftfull indexering (B-träd, hash, fulltext) samt ett moget ekosystem med replikering och säkerhetskopiering. Använd SQL när era data är starkt relationsbaserade, konsistens är avgörande och frågorna är komplexa och varierade.
# SQL excels at: complex queries, joins, transactions
# Example: find top 5 products by revenue this month
sql_query = '''
SELECT p.name, SUM(oi.quantity * oi.price) AS revenue
FROM orders o
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id
WHERE o.created_at >= DATE_TRUNC('month', NOW())
GROUP BY p.id, p.name
ORDER BY revenue DESC
LIMIT 5;
'''
print('SQL shines for relational queries with JOINs:')
print(sql_query)
print('ACID guarantees example (transfer $100 between accounts):')
transfer_sql = '''
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT; -- either both succeed or neither does
'''
print(transfer_sql)Utmaningar vid skalning av SQL
SQL-databaser skalar naturligt vertikalt (större server, mer CPU/RAM), men horisontell skalning är komplex. Läsrepliker hanterar läsintensiva arbetslaster genom att dirigera läsningar till repliknoder och skrivningar till primärnoden. Skrivgenomströmningen är dock begränsad till en enda primärnod om ni inte lägger till sharding.
Sharding partitionerar data över flera DB-instanser med hjälp av en shard-nyckel (t.ex. user_id mod N). Det ger skalning av skrivningar, men förstör möjligheten att effektivt utföra joins och transaktioner över shards — två av SQL:s starkaste funktioner. De flesta webbapplikationer växer ur SQL på en enda nod vid omkring 5–10 TB data eller cirka 100 000 skrivningar per sekund.
# SQL scaling strategies
strategies = {
'Read replicas': {
'how': 'One primary (writes), multiple replicas (reads)',
'scales': 'Read throughput (10x+)',
'limit': 'Write throughput still bounded by single primary',
},
'Connection pooling (PgBouncer)': {
'how': 'Pool of persistent DB connections shared among app servers',
'scales': 'Connection count (PostgreSQL max ~500 connections)',
'limit': 'Does not increase query throughput',
},
'Horizontal sharding': {
'how': 'Partition rows by shard key across N database instances',
'scales': 'Both reads and writes (N×)',
'limit': 'Cross-shard joins and transactions broken; complex routing',
},
'CQRS': {
'how': 'Separate write model (SQL) from read model (denormalised/NoSQL)',
'scales': 'Optimise each path independently',
'limit': 'Eventual consistency between write and read models',
},
}
for strategy, info in strategies.items():
print(f'{strategy}:\n How: {info["how"]}\n Scales: {info["scales"]}\n Limit: {info["limit"]}\n')Nyckel-värde-datalager: Redis och DynamoDB
Nyckel-värde-datalager lagrar data som nyckel → värde-par och erbjuder O(1)-läsning och -skrivning baserat på nyckeln. De ger avkall på flexibilitet i frågor för extrem prestanda och horisontell skalbarhet. Redis (i minnet) uppnår latens på mikrosekundsnivå, medan DynamoDB (hanterad tjänst) uppnår latens på ensiffriga millisekundsnivåer och kan skalas automatiskt till valfri genomströmning.
Använd nyckel-värde-datalager för: sessionslagring, cachning, funktionsflaggor, kopplingar för URL-förkortare, kundvagnar och topplistor i realtid. Använd dem inte när ni behöver: komplexa frågor, relationer mellan entiteter eller ad hoc-filtrering — ni kan bara slå upp data med en exakt nyckel.
# Key-value store use cases
kv_operations = {
'GET key': 'O(1) point lookup — the core operation',
'SET key value': 'O(1) insert or update',
'DEL key': 'O(1) delete',
'EXPIRE key ttl': 'Set time-to-live; key auto-deleted after ttl seconds',
'INCR key': 'Atomic increment — useful for counters and rate limiting',
'LPUSH/LRANGE': 'List operations — useful for queues and recent-items feeds',
'ZADD/ZRANGE': 'Sorted set — leaderboards, rate limiting with sliding window',
}
print('Redis operation set:')
for op, desc in kv_operations.items():
print(f' {op:25s}: {desc}')
print('\nDynamoDB vs Redis:')
print(' Redis: microsecond latency, in-memory, needs persistence config')
print(' DynamoDB: single-digit ms, managed, auto-scaling, durable by default')Dokumentdatalager: MongoDB
Dokumentdatalager (MongoDB, Couchbase) lagrar data som JSON-liknande dokument och tillåter flexibla scheman — fält kan skilja sig åt mellan dokument i samma samling. De stöder indexering på valfritt fält och relativt avancerade frågor (filter, projektioner, aggregeringar), även om transaktioner över flera dokument är mer begränsade än i SQL.
Dokumentdatalager passar för applikationer där: datastrukturen varierar mellan entiteter (användarprofiler med olika attribut), snabb utveckling av schemat förväntas (startupföretag som ofta ändrar sina datamodeller) eller läsmönstren främst består av att hämta hela entiteter i stället för att sammanfoga tabeller.
# MongoDB document example
user_doc = {
'_id': 'user123',
'name': 'Alice',
'email': 'alice@example.com',
'preferences': {
'theme': 'dark',
'language': 'en',
'notifications': ['email', 'push']
},
'addresses': [
{'type': 'home', 'city': 'Berlin', 'country': 'DE'},
{'type': 'work', 'city': 'Munich', 'country': 'DE'}
],
'subscription_tier': 'pro',
# Note: not all users have all fields -- flexible schema!
}
import json
print('Document structure (flexible schema):')
print(json.dumps(user_doc, indent=2))
print('\nDocument store strengths:')
print(' - Nested/array fields without joins')
print(' - Flexible schema (different fields per document)')
print(' - Scales horizontally by sharding on _id')Bredkolumnslager: Cassandra
Bredkolumnslager (Apache Cassandra, HBase) lagrar data i rader och kolumner, men tillåter att varje rad har en egen uppsättning kolumner. De är utformade för massiv skrivgenomströmning fördelad över många noder, med eventuell konsistens som standard. Cassandra skalar skrivningar linjärt — en fördubbling av antalet noder fördubblar skrivgenomströmningen.
Avvägningen är att frågor måste utformas kring partitionsnyckeln. Ni kan inte effektivt filtrera eller sortera på godtyckliga kolumner — ni måste först definiera frågemönstret och därefter utforma tabellen så att den passar. Detta är motsatsen till SQL:s metod ”utforma data först och skriv sedan valfria frågor”.
# Cassandra table design for time-series events
# Design around the query: 'give me all events for user X, most recent first'
cassandra_table = '''
CREATE TABLE user_events (
user_id UUID,
event_time TIMESTAMP,
event_type TEXT,
metadata MAP<TEXT, TEXT>,
PRIMARY KEY (user_id, event_time)
) WITH CLUSTERING ORDER BY (event_time DESC);
-- Query (matches partition key exactly):
SELECT * FROM user_events WHERE user_id = ? LIMIT 100;
'''
print('Cassandra wide-column design:')
print(cassandra_table)
print('Properties:')
print(' - user_id = partition key (all rows for one user on same node)')
print(' - event_time = clustering key (sorted within partition)')
print(' - Very fast writes: append-only, no locking')
print(' - Cannot query by event_type alone (no partition key)')CAP-teoremet: konsistens, tillgänglighet och partitionstolerans
CAP-teoremet säger att ett distribuerat system kan garantera högst två av följande: konsistens (varje läsning returnerar den senaste skrivningen), tillgänglighet (varje begäran får ett svar som inte är ett fel) och partitionstolerans (systemet fortsätter fungera trots nätverkspartitioner).
Eftersom nätverkspartitioner alltid inträffar i distribuerade system är den verkliga avvägningen mellan CP (prioriterar konsistens och kan avvisa begäranden under en partition) och AP (prioriterar tillgänglighet och kan returnera inaktuella data). SQL-databaser är i allmänhet CP, medan Cassandra och DynamoDB är AP (eventuell konsistens som standard). Redis Cluster är CP.
# CAP theorem applied to common databases
databases = {
'PostgreSQL (single node)': {'C': True, 'A': True, 'P': False, 'note': 'Not distributed; CA'},
'PostgreSQL (multi-AZ)': {'C': True, 'A': False, 'P': True, 'note': 'CP: primary fails over, brief downtime'},
'MySQL Cluster': {'C': True, 'A': False, 'P': True, 'note': 'CP'},
'Cassandra': {'C': False, 'A': True, 'P': True, 'note': 'AP: eventual consistency default'},
'DynamoDB (default)': {'C': False, 'A': True, 'P': True, 'note': 'AP: eventual consistency'},
'DynamoDB (strong read)': {'C': True, 'A': False, 'P': True, 'note': 'CP: strongly consistent reads'},
'Redis Cluster': {'C': True, 'A': False, 'P': True, 'note': 'CP'},
'MongoDB (default)': {'C': True, 'A': False, 'P': True, 'note': 'CP: reads from primary'},
}
for db, caps in databases.items():
c_str = 'C' if caps['C'] else '-'
a_str = 'A' if caps['A'] else '-'
p_str = 'P' if caps['P'] else '-'
print(f'{db:35s} [{c_str}{a_str}{p_str}] {caps["note"]}')Att välja lagring: ett beslutsramverk
Ett praktiskt beslutsramverk för val av lagring i intervjuer:
- Behöver ni ACID-transaktioner? → Relationsdatabas (PostgreSQL, MySQL)
- Behöver ni uppslagningar på under en millisekund eller cachning? → Nyckel-värde-datalager (Redis)
- Behöver ni ett flexibelt schema eller dokumentorienterade data? → Dokumentdatalager (MongoDB)
- Behöver ni massiv skrivgenomströmning (>100K/sekund) med tidsserie- eller händelsedata? → Bredkolumnslager (Cassandra)
- Behöver ni global distribution med hanterad skalning? → DynamoDB eller Cosmos DB
- Behöver ni traverseringar i grafer? → Grafdatabas (Neo4j)
# Decision tree in code form
def choose_storage(needs_acid, high_write_throughput, flexible_schema,
sub_ms_latency, graph_queries, global_scale):
if sub_ms_latency:
return 'Redis (in-memory key-value)'
if graph_queries:
return 'Neo4j (graph database)'
if needs_acid:
return 'PostgreSQL / MySQL (relational)'
if high_write_throughput and not flexible_schema:
return 'Cassandra (wide-column, write-optimised)'
if flexible_schema:
return 'MongoDB (document store)'
if global_scale:
return 'DynamoDB or Cosmos DB (managed global KV/document)'
return 'PostgreSQL (safe default for most web apps)'
# Example scenarios
scenarios = [
{'needs_acid': True, 'high_write_throughput': False, 'flexible_schema': False,
'sub_ms_latency': False, 'graph_queries': False, 'global_scale': False},
{'needs_acid': False, 'high_write_throughput': True, 'flexible_schema': False,
'sub_ms_latency': False, 'graph_queries': False, 'global_scale': False},
{'needs_acid': False, 'high_write_throughput': False, 'flexible_schema': False,
'sub_ms_latency': True, 'graph_queries': False, 'global_scale': False},
]
for s in scenarios:
print(f'{choose_storage(**s)}')Polyglot Persistence: använda flera datalager
Produktionssystem använder sällan en enda databas för allt. Polyglot persistence innebär att använda rätt lagringsteknik för varje del av systemet. En typisk webbapplikation kan använda: PostgreSQL som primär källa för användar- och orderdata, Redis för sessionslagring och cachning, Elasticsearch för fulltextsökning, S3 för fillagring och Cassandra för händelseloggar och analys.
Avvägningen är att den operativa komplexiteten ökar med varje databastyp. Teamet måste underhålla, övervaka och säkerhetskopiera flera system. Motiveringen är att prestanda- och skalningsvinsterna av att matcha varje arbetsbelastning med rätt lagring överväger den operativa kostnaden i stor skala.
# Polyglot persistence in an e-commerce system
components = {
'User accounts, orders, payments': {
'storage': 'PostgreSQL',
'reason': 'ACID transactions (payment integrity), complex queries',
},
'Product catalogue': {
'storage': 'MongoDB or PostgreSQL with JSONB',
'reason': 'Flexible product attributes vary by category',
},
'Session tokens': {
'storage': 'Redis (with TTL)',
'reason': 'O(1) lookup, automatic expiry, high throughput',
},
'Product search': {
'storage': 'Elasticsearch',
'reason': 'Full-text search, faceted filtering, relevance scoring',
},
'Activity/event log': {
'storage': 'Cassandra or Kafka + S3',
'reason': 'High write throughput, append-only, time-series queries',
},
'Product images / videos': {
'storage': 'S3 + CloudFront CDN',
'reason': 'Cheap object storage, global distribution via CDN',
},
}
for component, info in components.items():
print(f'{component}:\n {info["storage"]}: {info["reason"]}\n')Indexeringsstrategier för olika lagringstyper
Alla lagringssystem använder index för att snabba upp läsningar, på bekostnad av långsammare skrivningar och extra lagringsutrymme. Att förstå indexering för olika lagringstyper är avgörande inom systemdesign:
- SQL: B-trädindex på valfri kolumn; sammansatta index för frågor med flera kolumner; täckande index för att undvika uppslagningar i tabellen
- MongoDB: Index på valfritt fält; sammansatta index; TTL-index för automatisk utgång
- Cassandra: Endast partitionsnyckeln och klustringskolumner indexeras inbyggt; sekundära index är kostsamma
- Redis: Sorterade mängder som index för intervallfrågor; traditionell indexering behövs inte för nyckel-värde-data
# Indexing examples across storage types
# PostgreSQL: B-tree composite index
postgres_index = '''
CREATE INDEX idx_orders_user_created
ON orders(user_id, created_at DESC);
-- Optimises: SELECT * FROM orders WHERE user_id=? ORDER BY created_at DESC
'''
# MongoDB: compound index
mongo_index = '''
db.products.createIndex({ category: 1, price: -1 })
// Optimises: db.products.find({category:'Electronics'}).sort({price:-1})
'''
# Cassandra: cluster key ordering (built into table design)
cassandra_index = '''
-- No separate index needed; clustering key IS the index:
PRIMARY KEY (user_id, event_time) WITH CLUSTERING ORDER BY (event_time DESC)
'''
print('PostgreSQL:', postgres_index)
print('MongoDB:', mongo_index)
print('Cassandra:', cassandra_index)SQL kontra NoSQL i intervjuer: vad ni bör säga
När ni får frågan ”SQL eller NoSQL?” i en systemdesignintervju ska ni aldrig svara med ett enda ord. Följ i stället denna struktur:
- Ange arbetsbelastningen: ’Det här är läsintensivt med komplex filtrering, så …’
- Ange kravet: ’Vi behöver stark konsistens för finansiella transaktioner, så …’
- Ange valet: ’Jag skulle använda PostgreSQL med läsrepliker’
- Ange avvägningen: ’Avvägningen är att horisontell skalning av skrivningar kräver sharding, vilket ökar komplexiteten’
- Nämn ett alternativ: ’Om skrivningarna vore fler skulle vi kunna överväga DynamoDB’
# Sample answer structure for 'SQL or NoSQL?'
def answer_storage_question(workload, consistency_need, scale):
print(f'Workload: {workload}')
print(f'Consistency: {consistency_need}')
print(f'Scale: {scale}')
print()
if 'financial' in workload.lower() or consistency_need == 'strong':
choice = 'PostgreSQL (ACID, strong consistency)'
tradeoff = 'Horizontal write scaling requires sharding'
alternative = 'Google Spanner for global transactions'
elif 'event' in workload.lower() or 'log' in workload.lower():
choice = 'Cassandra (high write throughput, time-series)'
tradeoff = 'Eventual consistency; queries limited to partition key'
alternative = 'Kafka + S3 for long-term event archival'
else:
choice = 'DynamoDB (managed, auto-scale, low latency)'
tradeoff = 'Limited query flexibility; cross-item transactions limited'
alternative = 'PostgreSQL if complex queries emerge'
print(f'Choice: {choice}\nTrade-off: {tradeoff}\nAlternative: {alternative}')
answer_storage_question('Social media feed', 'eventual', '10M users')Snabbtest
Testa er förståelse av begreppen Data Structures & Algorithms — Coding Interview Prep från den här lektionen.
Sammanfattning av lektionen
I den här lektionen lärde ni er: SQL-databaser erbjuder ACID-transaktioner och komplexa frågor, men har svårt att skala skrivningar, medan NoSQL-databaser byter konsistens eller flexibilitet i frågor mot extrem skalbarhet och tillgänglighet, CAP-teoremet tvingar distribuerade system att välja mellan konsistens och tillgänglighet under nätverkspartitioner, och produktionssystem använder vanligtvis polyglot persistence — varje arbetsbelastning matchas med rätt lagringsmotor. Nästa steg är att utforska cachelager, CDN:er och lastbalansering för att skala läsintensiva system ytterligare.
Lär dig Förberedelse inför kodningsintervjuer med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 90
- Lektioner
- 360
Vanliga frågor
Är lektionen ”Skalbar datalagring: SQL eller NoSQL” gratis?
Ja – hela texten till ”Skalbar datalagring: SQL eller NoSQL” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Förberedelse inför kodningsintervjuer, kan Ni uppgradera till CoddyKit PRO. Kursen i Förberedelse inför kodningsintervjuer innehåller totalt 4 lektioner.
Vad lär jag mig i ”Skalbar datalagring: SQL eller NoSQL”?
Välj mellan relationsdatabaser, key-value-databaser, dokumentdatabaser och wide-column-databaser utifrån åtkomstmönster, konsekvenskrav och skalbarhetsbehov. Ni övar på Förberedelse inför kodningsintervjuer med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Förberedelse inför kodningsintervjuer?
Du behöver inga förkunskaper. Utbildningen i Förberedelse inför kodningsintervjuer på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.
Hur lång tid tar lektionen ”Skalbar datalagring: SQL eller NoSQL”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Förberedelse inför kodningsintervjuer-lektionen?
Ja. Varje Förberedelse inför kodningsintervjuer-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Ramverk för systemdesignintervjuer
- Skalbar datalagring: SQL eller NoSQL
- Caching, CDN:er och lastbalansering
- Designa Rate Limiter och Twitter Feed