DROP TABLE Safety Guide
Learn from costly mistakes! Master table deletion safety, recovery strategies, and production best practices. One wrong DROP = hours of downtime + thousands lost!
๐ Discord's 5 Billion Messages/Day
The Challenge
5 BILLION messages every single day from 150M+ active users
- 57,870 messages/second average
- 120,000+ messages/second at peak
- ~2 TB of new data daily
- <50ms response time required
How They Do It
1. Smart Table Design
2. Batch Writes - Reduces network round trips by 90%, improves latency from 30ms โ 5ms
3. TTL for Efficiency - Auto-expire temporary messages after 30 days, saves 40% storage
4. Async Inserts - Message appears instantly (<5ms), database write happens in background
The Results
- โ 120,000 INSERTs/second
- โ <5ms latency (user-facing)
- โ 40% storage savings (TTL cleanup)
- โ 99.99% uptime
๐ INSERT Basics
Basic Syntax
Key Points
- Column order doesn't matter - As long as values match column names
- All PRIMARY KEY columns required - Cannot be NULL
- Non-key columns optional - Will be NULL if omitted
- No RETURNING clause - INSERT doesn't return inserted data
Data Type Examples
โ๏ธ INSERT vs UPDATE: They're the SAME!
๐คฏ Mind-Blowing Fact
In Cassandra, INSERT and UPDATE are IDENTICAL operations!
Both perform an "UPSERT" - if the row exists, it's updated; if not, it's inserted.
INSERT
What happens:
- If U001 doesn't exist โ creates new row
- If U001 exists โ overwrites name column
UPDATE
What happens:
- If U001 doesn't exist โ creates new row
- If U001 exists โ overwrites name column
Exactly the same result! This is called "UPSERT" behavior.
Why This Matters
When to Use Each
- Use INSERT: When inserting ALL or MOST columns
- Use UPDATE: When updating SPECIFIC columns (more readable)
- Performance: Identical! Choose based on readability
โ๏ธ How INSERT Works Internally
The Write Path (4 Steps)
- Step 1: Commit Log - Write to append-only log on disk (crash recovery)
- Step 2: Memtable - Write to in-memory structure (fast!)
- Step 3: Respond to Client - "Success!" (before hitting disk!)
- Step 4: Flush to SSTable - Eventually written to disk (async)
Detailed Write Path
Why So Fast?
- No disk seeks - Sequential append-only writes (commit log)
- No indexes to update - Unlike SQL databases
- No locks - No transaction coordination needed
- In-memory writes - Memtable in RAM
- Async disk writes - SSTables written later
Performance Numbers
- Single INSERT latency: 1-5ms average
- Throughput: 10,000-50,000 writes/sec per node
- Batch INSERT: 50,000-150,000 writes/sec per node
- Cluster throughput: Scales linearly (10 nodes = 10x throughput)
๐ฆ Batch Operations
LOGGED vs UNLOGGED Batch
LOGGED (Default)
Guarantees:
- โ All-or-nothing (atomic)
- โ Writes to batchlog first
- โ ๏ธ Slower (extra overhead)
Use when: Writes to SAME partition, atomicity critical
UNLOGGED (Fast)
Guarantees:
- โ Much faster (no batchlog)
- โ ๏ธ NOT atomic
- โ Fewer network round trips
Use when: Performance matters, atomicity not needed
Batch Example: Insert Multiple Users
โ ๏ธ Batch Anti-Patterns
- DON'T batch writes to different partitions - Actually SLOWER!
- DON'T batch 100+ statements - Coordinator bottleneck
- DON'T use LOGGED for performance - Use UNLOGGED instead
Rule of thumb: Batch 5-50 statements to SAME partition
โฐ TTL (Time To Live)
What is TTL?
TTL: Automatic data expiration. Cassandra deletes data after N seconds.
Real-World TTL Examples
Session Storage
Benefit: No manual cleanup needed, saves storage
Cache Data
Benefit: Auto-invalidate stale cache
Temporary Messages
Benefit: Compliance, storage savings
Discord's TTL Strategy
Discord uses TTL for temporary channels and DM message previews:
- Temporary channels: 30-day TTL saves 40% storage
- Message previews: 7-day TTL for quick access
- Result: $2M+ annual savings on storage costs
๐ Timestamps & Conflict Resolution
Default Behavior: Last Write Wins
USING TIMESTAMP (Custom Timestamps)
When to Use Custom Timestamps
- Offline sync: Mobile apps syncing old changes
- Batch imports: Preserving original creation time
- Event sourcing: Replay events with original timestamps
- Testing: Deterministic test scenarios
Check Timestamp (Writetime)
๐ LWT: IF NOT EXISTS
What are Lightweight Transactions?
LWT: Atomic compare-and-set operations. Ensures uniqueness or conditional writes.
Performance Cost
Regular INSERT
- Latency: 1-5ms
- Throughput: 50K writes/sec
- Consistency: Eventually consistent
LWT INSERT
- Latency: 20-50ms (4-10x slower!)
- Throughput: 5K writes/sec (10x slower!)
- Consistency: Linearizable (Paxos)
โ ๏ธ Use LWT Sparingly!
LWT uses Paxos consensus: Requires 4 round trips instead of 1
- โ Use for: Unique constraints, critical atomicity (user registration)
- โ Don't use for: Regular writes, high-throughput operations
- ๐ก Better alternative: Application-level uniqueness checks
โก Performance Optimization
1. Async Writes (Application Level)
2. Prepared Statements
3. Batch Size Tuning
Performance Metrics
Production Benchmarks
| Operation | Latency | Throughput (per node) |
|---|---|---|
| Single INSERT | 1-5ms | 10K-50K writes/sec |
| Batch INSERT (UNLOGGED) | 3-10ms | 50K-150K writes/sec |
| Prepared statement | 0.5-3ms | 100K+ writes/sec |
| LWT (IF NOT EXISTS) | 20-50ms | 5K-10K writes/sec |
๐ฅ๏ธ Interactive INSERT Console
Try the examples or write your own INSERT statements.
This simulator shows you what happens internally!
๐ข Real-World Production Examples
Netflix: Viewing History
Scale: 200M users, 500M inserts/day
Challenge: Personalized recommendations based on watch history
Uber: Driver Locations
Scale: 5M drivers, 15M updates/minute
TTL: 5-minute auto-expiration keeps data fresh
Apple: Health Data
Scale: 1B+ devices, 100B datapoints/day
Partitioning: By user_id + date prevents hotspots
โญ Best Practices
DO's
- Use prepared statements for repeated inserts (50-70% faster)
- Batch 20-50 statements to same partition
- Use UNLOGGED batches for better performance
- Add TTL for temporary/cache data
- Use async writes in applications
- Monitor write latency and throughput
- Test with production load before deploying
- Use correct data types (UUID not TEXT for IDs)
- Partition by time for time-series data
- Set realistic TTL values based on use case
DON'Ts
- Don't batch to different partitions (slower!)
- Don't use LWT unnecessarily (10x slower)
- Don't batch >100 statements (coordinator bottleneck)
- Don't reparse queries (use prepared statements)
- Don't synchronously wait (use async)
- Don't insert NULL values (waste space)
- Don't use sequential IDs (use UUID/TIMEUUID)
- Don't forget timestamps (add created_at/updated_at)
- Don't ignore errors (handle write failures)
- Don't skip monitoring (track write metrics)
Production Checklist
- โ Schema design validated with expected query patterns
- โ Prepared statements implemented for all repeated INSERTs
- โ Batch size optimized (20-50 statements to same partition)
- โ TTL configured for temporary data (sessions, cache)
- โ Async writes implemented in application layer
- โ Error handling with retry logic and circuit breakers
- โ Monitoring dashboards for write latency and throughput
- โ Load testing completed at 2x expected peak traffic
- โ Alerts configured for high write latency (>100ms)
- โ Runbook documented for common write issues
โ Common Mistakes & Fixes
Mistake #1: Batching to Different Partitions
Mistake #2: Using LWT for Everything
Mistake #3: Not Using Prepared Statements
Mistake #4: Synchronous Writes in Web Apps
๐ผ Interview Questions & Answers
Answer:
Why They're the Same:
Both INSERT and UPDATE perform an "upsert" operation. Cassandra doesn't check if a row exists before writingโit simply writes the new data with a timestamp. This is because:
- No read-before-write: Checking existence would require reading from disk (slow)
- Last-write-wins: Conflicts resolved by timestamp, not existence
- Performance: Avoids the overhead of existence checks
Implications:
- 1. No INSERT errors: Running INSERT twice won't failโit just overwrites
- 2. Unintentional overwrites: Must use IF NOT EXISTS for uniqueness
- 3. Tombstones: UPDATE can create rows even if they didn't exist
- 4. Application logic: Can't rely on INSERT vs UPDATE distinction
Example:
Answer:
LOGGED Batch:
- Guarantee: All-or-nothing atomicity (all succeed or all fail)
- Mechanism: Writes to batchlog first, then applies statements
- Cost: ~30% performance overhead
- Use when: Atomicity critical (e.g., debit + credit operations)
UNLOGGED Batch:
- Guarantee: No atomicity (some might succeed, others fail)
- Mechanism: Directly applies statements, no batchlog
- Cost: Minimal overhead
- Use when: Performance matters, partial failures acceptable
Performance Comparison:
- LOGGED: ~15-25ms for 20 statements
- UNLOGGED: ~5-10ms for 20 statements (2-3x faster)
- Individual INSERTs: ~100-200ms for 20 statements (10-20x slower)
Best Practice:
Use UNLOGGED by default. Only use LOGGED when atomicity is truly required (e.g., financial transactions where partial success would cause data inconsistency).
Answer:
The Write Path (4 Steps):
- Commit Log: Sequential append to log file on disk (~0.5ms)
- Memtable: Write to in-memory sorted structure (~0.5ms)
- Respond: Send "success" to client (~1ms total)
- Flush (async): Eventually flush memtable to SSTable on disk
Why It's Fast:
- 1. Sequential writes: Commit log is append-only (no disk seeks)
- 2. In-memory writes: Memtable operations are RAM-speed
- 3. No indexes to update: Unlike SQL (B-tree updates)
- 4. No locks: No transaction coordination
- 5. Async disk writes: SSTables written later, not blocking
- 6. No read-before-write: Doesn't check if row exists
Comparison with SQL:
| Operation | SQL | Cassandra |
|---|---|---|
| Write latency | 5-20ms | 1-5ms |
| Index updates | Yes (slow) | No |
| Disk seeks | Random I/O | Sequential only |
| Locks | Row/page locks | None |
Answer (Comprehensive Strategy):
1. Use Prepared Statements
2. Parallel Execution
3. Batch Wisely (20-50 statements)
4. Tune Write Settings
- Consistency Level: Use ONE instead of QUORUM (3x faster)
- Connection pool: Increase to 10-20 connections per node
- Async execution: Don't wait for each write
5. Optimize Cassandra Settings
- Disable commitlog_sync: batch mode during bulk load
- Increase memtable_flush_writers: 4-8 writers
- Disable compaction: nodetool disableautocompaction (re-enable after)
Expected Performance:
- Sequential: 1,000-5,000 inserts/sec
- Optimized parallel: 50,000-150,000 inserts/sec per node
- Cluster (10 nodes): 500K-1.5M inserts/sec
Answer:
What is TTL:
Time To Live - automatic data expiration. Cassandra marks data with a timestamp and deletes it after N seconds. No manual cleanup needed.
Session Storage Design:
Benefits:
- 1. No manual cleanup: Sessions auto-expire
- 2. Storage savings: Prevents unbounded growth
- 3. Performance: No background cleanup jobs needed
- 4. Simple logic: Set and forget
Advanced Pattern - Sliding Window:
Production Considerations:
- Check remaining TTL: SELECT TTL(session_data) to warn user
- Grace period: Use 25 hours, warn at 24 hours
- Monitoring: Track tombstone creation rate
Responsive Ad