| name | databases-architecture-skill |
| description | Master database design (SQL, NoSQL), system architecture, API design (REST, GraphQL), and building scalable systems. Learn PostgreSQL, MongoDB, system design patterns, and enterprise architectures. |
Databases & Architecture Skill
Complete guide to designing databases, systems, and APIs that scale.
Quick Start
Learning Path
Data → Schema → APIs → Architecture
↓ ↓ ↓ ↓
SQL Normalize REST Microservices
NoSQL Indexes GraphQL Patterns
Get Started in 5 Steps
-
SQL Fundamentals (2-3 weeks)
- SELECT, INSERT, UPDATE, DELETE
- Joins and aggregations
-
Database Design (3-4 weeks)
- Normalization
- Entity-relationship modeling
- Indexing
-
NoSQL Databases (2-3 weeks)
- Document stores (MongoDB)
- Key-value (Redis)
- When to use each
-
API Design (3-4 weeks)
- REST principles
- GraphQL basics
- Error handling
-
System Architecture (ongoing)
- Scalability patterns
- Caching strategies
- Distributed systems
SQL Databases
SQL Fundamentals
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE,
age INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO users (name, email, age)
VALUES ('Alice', 'alice@example.com', 25);
SELECT * FROM users;
SELECT name, email FROM users;
SELECT * FROM users WHERE age > 25;
SELECT * FROM users WHERE age >= 25 AND age <= 35;
SELECT * FROM users WHERE name LIKE 'A%';
SELECT * FROM users ORDER BY age DESC;
SELECT * FROM users LIMIT 10 OFFSET 20;
Advanced SQL
SELECT users.name, orders.amount
FROM users
INNER JOIN orders ON users.id = orders.user_id;
SELECT users.name, COUNT(orders.id) as order_count
FROM users
LEFT JOIN orders ON users.id = orders.user_id
GROUP BY users.id, users.name;
SELECT age, COUNT(*) as count, AVG(salary) as avg_salary
FROM users
GROUP BY age
HAVING COUNT(*) > 5;
SELECT name, salary,
AVG(salary) OVER (PARTITION BY department) as dept_avg,
RANK() OVER (ORDER BY salary DESC) as salary_rank
FROM employees;
WITH high_earners AS (
SELECT employees salary
)
department, () count
high_earners
department;
users age name ;
users age ;
Database Design
Normalization (Reduce data redundancy):
1NF: Each column has atomic value
2NF: Remove partial dependencies
3NF: Remove transitive dependencies
BCNF: Every determinant is a candidate key
Example - Poor vs Good Design:
CREATE TABLE students (
id INT PRIMARY KEY,
name VARCHAR(255),
course1 VARCHAR(255),
course2 VARCHAR(255),
course3 VARCHAR(255),
teacher1 VARCHAR(255),
teacher2 VARCHAR(255)
);
CREATE TABLE students (
id INT PRIMARY KEY,
name VARCHAR(255)
);
CREATE TABLE courses (
id INT PRIMARY KEY,
name VARCHAR(255),
teacher_id INT FOREIGN KEY
);
CREATE TABLE enrollments (
student_id INT FOREIGN KEY,
course_id INT FOREIGN KEY,
PRIMARY KEY (student_id, course_id)
);
Indexing & Performance
CREATE INDEX idx_email ON users(email);
CREATE INDEX idx_age_salary ON users(age, salary);
EXPLAIN SELECT * FROM users WHERE email = 'alice@example.com';
PostgreSQL Advanced
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(255),
metadata JSONB
);
INSERT INTO products VALUES (1, 'Laptop', '{"color": "silver", "specs": {"cpu": "M1"}}');
SELECT * FROM products WHERE metadata->>'color' = 'silver';
SELECT * FROM products WHERE metadata->'specs'->>'cpu' = 'M1';
CREATE TABLE tags (
id SERIAL PRIMARY KEY,
article_id INT,
tags TEXT[]
);
SELECT * FROM tags WHERE 'database' = ANY(tags);
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
title VARCHAR(255),
content TEXT,
search_vector tsvector
);
UPDATE articles SET search_vector = to_tsvector('english', title content);
articles search_vector @@ to_tsquery();
NoSQL Databases
MongoDB Document Storage
db.users.insertOne({
_id: ObjectId(),
name: "Alice",
email: "alice@example.com",
age: 25,
tags: ["developer", "python"],
address: {
street: "123 Main St",
city: "New York",
zip: "10001"
}
});
db.users.find({ name: "Alice" });
db.users.find({ age: { $gt: 25 } });
db.users.find({ tags: "python" });
db.users.updateOne(
{ name: "Alice" },
{ $set: { age: 26 } }
);
db.users.updateOne(
{ _id: ObjectId(...) },
{ $push: { tags: "javascript" } }
);
db..([
{ : { : { : } } },
{ : { : , : { : } } },
{ : { : - } }
]);
db..({ : });
db..({ : , : });
db..({ : });
Redis Caching
import redis
r = redis.Redis(host='localhost', port=6379)
r.set('user:1:name', 'Alice')
r.get('user:1:name')
r.incr('page:views')
r.setex('token:xyz', 3600, 'valid')
r.lpush('queue:jobs', 'job1', 'job2')
r.rpop('queue:jobs')
r.llen('queue:jobs')
r.sadd('tags:post:1', 'python', 'database', 'backend')
r.smembers('tags:post:1')
r.sismember('tags:post:1', 'python')
r.hset('user:1', mapping={'name': 'Alice', 'email': 'alice@example.com'})
r.hgetall('user:1')
r.publish('channel:notifications', 'New message')
pipe = r.pipeline()
pipe.set('key1', 'value1')
pipe.set('key2', 'value2')
pipe.execute()
API Design
REST API Best Practices
HTTP Methods:
GET - Retrieve resource (safe, idempotent)
POST - Create resource
PUT - Replace entire resource (idempotent)
PATCH - Partial update
DELETE - Remove resource (idempotent)
Status Codes:
200 OK - Success
201 Created - Resource created
204 No Content - Success, no body
400 Bad Request - Client error
401 Unauthorized - Auth required
403 Forbidden - Not allowed
404 Not Found - Resource missing
500 Internal Server Error
Resource URLs:
GET /api/users # List all
GET /api/users/:id # Get one
POST /api/users # Create
PUT /api/users/:id # Update (full)
PATCH /api/users/:id # Update (partial)
DELETE /api/users/:id # Delete
// Nested resources
GET /api/users/:id/posts # User's posts
POST /api/users/:id/posts # Create post for user
Request/Response Example:
POST /api/users
Content-Type: application/json
{
"name": "Alice",
"email": "alice@example.com",
"age": 25
}
Response (201 Created):
{
"id": 123,
"name": "Alice",
"email": "alice@example.com",
"age": 25,
"created_at": "2024-01-15T10:30:00Z"
}
GraphQL
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
}
type Query {
user(id: ID!): User
users(limit: Int): [User!]!
post(id: ID!): Post
}
createUser String, String User
updateUser ID, String User
deleteUser ID Boolean
query GetUserWithPosts {
user(id: "123") {
name
email
posts {
title
id
}
}
}
mutation CreateUser {
createUser(name: "Alice", email: "alice@example.com") {
id
name
email
}
}
GraphQL vs REST:
| Aspect | REST | GraphQL |
|---|
| Over-fetching | Common | None |
| Under-fetching | Need multiple requests | Single query |
| Caching | Easy (HTTP caching) | More complex |
| Learning curve | Low | High |
| Use case | Simple CRUD | Complex, nested data |
System Design & Architecture
Scalability Patterns
Vertical Scaling (Scale Up):
- Add more CPU, RAM, storage
- Simple but has limits
- Single point of failure
Horizontal Scaling (Scale Out):
- Add more servers
- Load balancing needed
- Better resilience
Caching Strategy
Cache Levels:
1. Client-side (browser cache)
2. CDN (edge caching)
3. Application cache (Redis, Memcached)
4. Database (query caching)
Cache Invalidation Strategies:
1. TTL (Time to Live) - Automatic expiration
2. Event-based - Invalidate on change
3. Purge - Manual invalidation
Microservices Architecture
Advantages:
✓ Independent scaling
✓ Technology diversity
✓ Faster deployment
Challenges:
✗ Network latency
✗ Distributed transactions
✗ Operational complexity
Pattern:
API Gateway → Services → Databases
↓
Service Discovery
Message Queue
Logging/Monitoring
Database Sharding
Split data across multiple databases
- Range-based: User ID 1-1000 → DB1, 1001-2000 → DB2
- Hash-based: hash(user_id) % num_shards
- Directory-based: Lookup table maps to shard
Tradeoffs:
✓ Horizontal scaling
✗ Complex queries
✗ Operational overhead
Learning Checklist
Source: https://roadmap.sh/sql, https://roadmap.sh/system-design, https://roadmap.sh/api-design