Section 9: Advanced Operations

Master BATCH Operations

Complete guide to batch operations in Cassandra - logged vs unlogged batches, atomicity, performance optimization, and when NOT to use batches!

🎯 BATCH in Cassandra

CRITICAL: BATCH is NOT for Performance!

BIGGEST MISCONCEPTION: Many developers think BATCH makes writes faster. IT DOESN'T! In fact, BATCH can make writes SLOWER!

⚠️ BATCH is ONLY for:
  1. Atomicity: Ensuring multiple writes succeed or fail together
  2. Same Partition: Multiple operations to THE SAME partition key

Using BATCH for "bulk inserts" or "performance" is an ANTI-PATTERN!

⚠️ BATCH Performance: MYTH vs REALITY ❌ MYTH: "BATCH = Faster!" Developer's Wrong Assumption: "I'll group 1000 inserts in BATCH" "→ One network call = FAST!" What Actually Happens: 1️⃣ Coordinator Bottleneck • Coordinator must hold ALL 1000 writes in memory • Can cause Out Of Memory errors! 2️⃣ Sequential Processing • All writes wait for SLOWEST one to complete • No parallelism = SLOW! 3️⃣ Batchlog Overhead (if logged) • Writes entire batch to batchlog first (3 replicas!) • Then writes actual data • Double the work! RESULT: 2-10x SLOWER! Plus: Timeouts, OOM errors, Cluster instability ✅ REALITY: Parallel Individual Writes Smart Developer's Approach: "Send 1000 writes individually" "→ In PARALLEL using async/await!" What Actually Happens: 1️⃣ True Parallelism • Each write goes directly to responsible node • All 1000 writes happen SIMULTANEOUSLY! 2️⃣ No Coordinator Bottleneck • Load distributed across ALL nodes • No single point of failure 3️⃣ No Batchlog Overhead • Direct writes to data nodes • No extra logging • Minimal overhead! RESULT: 10x FASTER! Plus: Stable cluster, Predictable performance 💡 Golden Rule: Use BATCH for ATOMICITY (correctness), NEVER for PERFORMANCE (speed)!

📚 Beginner's Guide to BATCH

What is BATCH?

Simple Explanation: BATCH lets you group multiple INSERT, UPDATE, or DELETE statements together.

🏦 Bank Transfer Analogy:

Imagine transferring money between two bank accounts:

  • Without BATCH:
    • Step 1: Deduct $100 from Account A → Success ✓
    • Step 2: Add $100 to Account B → FAILS ✗
    • Problem: Money vanished! Account A lost $100, Account B didn't receive it!
  • With BATCH:
    • Both operations happen together as ONE unit
    • Either BOTH succeed, or BOTH fail
    • Safe: No money lost!
🚨 Common Misunderstanding:

Wrong Thinking: "I have 10,000 rows to insert. Let me put them in a BATCH to make it faster!"

Reality: This will make it MUCH SLOWER because:

  • BATCH adds overhead (logging, coordination)
  • Coordinator node becomes bottleneck
  • All writes wait for slowest one to complete

💡 For bulk inserts: Send individual writes in parallel, NOT in a BATCH!

📖 BATCH Syntax

Basic BATCH Syntax

BATCH Syntax
BEGIN [UNLOGGED] BATCH
[USING TIMESTAMP timestamp]

  INSERT INTO table1 (...) VALUES (...);
  UPDATE table2 SET ... WHERE ...;
  DELETE FROM table3 WHERE ...;

APPLY BATCH;

-- Logged BATCH (default - ensures atomicity)
BEGIN BATCH
  INSERT INTO users (user_id, name) VALUES (?, ?);
  INSERT INTO user_emails (email, user_id) VALUES (?, ?);
APPLY BATCH;

-- Unlogged BATCH (no atomicity guarantee)
BEGIN UNLOGGED BATCH
  INSERT INTO logs (log_id, message) VALUES (?, ?);
  INSERT INTO logs (log_id, message) VALUES (?, ?);
APPLY BATCH;

BATCH Rules

  • Can contain INSERT, UPDATE, DELETE statements
  • All statements share same timestamp (if specified)
  • Cannot contain SELECT statements
  • Cannot contain other BATCH statements (no nesting)
  • Recommended: Keep batches small (5-10 statements)

📝 Logged BATCH (Default)

Understanding Logged BATCH

What "Logged" Means: Cassandra writes the entire batch to a special log (the batchlog) before executing it.

📝 Package Delivery Analogy:

Think of sending a package with "signature required":

  • Step 1: Delivery company writes down "Package for Alice: Address XYZ" in their permanent log
  • Step 2: Attempts delivery to Alice
  • Step 3a (Success): Alice signs, log updated "DELIVERED"
  • Step 3b (Failure): Alice not home, log says "RETRY TOMORROW"

The log ensures the package will EVENTUALLY be delivered, even if there are temporary failures!

✅ Logged BATCH Guarantees:
  1. Atomicity: All statements succeed together, or all fail together
  2. Durability: Written to batchlog first (survives failures)
  3. Eventual completion: Will retry automatically until all succeed

Use Case: When you NEED all operations to succeed (like bank transfer)

⚠️ Performance Cost:

Logged BATCH is SLOW because:

  • Extra write to batchlog (3 replicas)
  • Coordinator must wait for all operations
  • Additional read to check batchlog status

Typically 2-5x slower than individual writes!

Logged BATCH Example

-- User Registration: Must succeed together
BEGIN BATCH

  -- Create user record
  INSERT INTO users (user_id, username, email, created_at)
  VALUES (uuid(), 'alice', '[email protected]', toTimestamp(now()));

  -- Create email-to-user lookup (for login)
  INSERT INTO users_by_email (email, user_id, username)
  VALUES ('[email protected]', uuid(), 'alice');

  -- Initialize user preferences
  INSERT INTO user_preferences (user_id, theme, language)
  VALUES (uuid(), 'dark', 'en');

APPLY BATCH;

// ✅ All 3 tables updated together atomically
// ✅ If any fails, none are written

⚡ Unlogged BATCH

Understanding Unlogged BATCH

What "Unlogged" Means: Skips the batchlog - just groups statements together and sends them to nodes.

📬 Regular Mail Analogy:

Think of sending multiple letters together:

  • You put 5 letters in one envelope
  • Mail carrier delivers them as a group
  • BUT no tracking, no signature required
  • If delivery fails, some letters might be delivered, some might not

Faster delivery, but less guarantee!

✅ Unlogged BATCH Benefits:
  • Faster: No batchlog overhead
  • Groups requests: Single network call to coordinator
  • Same partition optimization: All writes to same partition sent together

Use Case: Multiple writes to SAME partition where atomicity isn't critical

❌ NO Atomicity Guarantee:

If coordinator fails mid-batch:

  • Some statements might succeed
  • Some statements might fail
  • No automatic retry
  • Application must handle partial failures

Only use when you don't care about some statements failing!

Unlogged BATCH Example

-- Writing logs: Same partition, no atomicity needed
BEGIN UNLOGGED BATCH

  -- All logs for same application (same partition)
  INSERT INTO app_logs (app_id, log_time, message)
  VALUES ('app-001', now(), 'User login successful');

  INSERT INTO app_logs (app_id, log_time, message)
  VALUES ('app-001', now(), 'Page view: /dashboard');

  INSERT INTO app_logs (app_id, log_time, message)
  VALUES ('app-001', now(), 'API call: GET /users');

APPLY BATCH;

// ✅ Efficient: All to same partition
// ✅ If one log fails, others still written (acceptable)

⚖️ Logged vs Unlogged BATCH

📝 Logged BATCH

  • ✓ Atomic (all-or-nothing)
  • ✓ Durable (batchlog survives failures)
  • ✓ Automatic retries
  • ✗ 2-5x slower
  • ✗ Extra writes (batchlog)
  • ✗ Coordinator bottleneck

Use for: Critical operations requiring atomicity

⚡ Unlogged BATCH

  • ✓ Faster (no batchlog)
  • ✓ Less overhead
  • ✓ Groups statements efficiently
  • ✗ NOT atomic
  • ✗ Partial failures possible
  • ✗ No automatic retry

Use for: Same-partition writes where failures OK

Feature Logged BATCH Unlogged BATCH
Atomicity ✓ Guaranteed ✗ Not guaranteed
Performance Slow (2-5x overhead) Faster
Batchlog Yes (written to 3 replicas) No
Retries Automatic None
Use Case Critical operations Same-partition writes

✅ When to Use BATCH

Valid BATCH Use Cases

1. Denormalized Data (Logged BATCH)

Scenario: You store same data in multiple tables for different query patterns

Example: User registration creates entries in users, users_by_email, and user_preferences

✓ Use logged BATCH to ensure all tables updated together

2. Same Partition Multiple Writes (Unlogged BATCH)

Scenario: Many INSERTs/UPDATEs to same partition key

Example: Writing multiple log entries for same application

✓ Use unlogged BATCH to group writes efficiently

3. Maintaining Consistency (Logged BATCH)

Scenario: Related writes that MUST succeed together

Example: Inventory deduction + order creation

✓ Use logged BATCH for critical consistency

❌ BATCH Anti-Patterns

DON'T Use BATCH For These!

❌ Anti-Pattern #1: Bulk Inserts
-- ❌ BAD: Using BATCH for 10,000 inserts
BEGIN BATCH
  INSERT INTO users ... -- 10,000 statements!
  INSERT INTO users ...
  -- ... 9,998 more ...
APPLY BATCH;

// ❌ Coordinator out of memory!
// ❌ Cluster instability!
// ❌ Timeout errors!

✓ CORRECT: Send individual writes in parallel using async/await!

❌ Anti-Pattern #2: Cross-Partition without Need
-- ❌ BAD: BATCH across different partition keys
BEGIN BATCH
  INSERT INTO users WHERE user_id = 'user1' ...
  INSERT INTO users WHERE user_id = 'user2' ...
  INSERT INTO users WHERE user_id = 'user3' ...
APPLY BATCH;

// ❌ Coordinator coordinates across multiple nodes
// ❌ Slower than individual writes!
❌ Anti-Pattern #3: Performance Optimization

Myth: "BATCH makes writes faster!"

Reality: BATCH adds overhead and makes writes SLOWER!

Only use BATCH for correctness (atomicity), never for performance!

💡 Real-World Examples

Example 1: User Registration

-- Denormalized tables must stay in sync
BEGIN BATCH

  -- Main user record
  INSERT INTO users (user_id, username, email, created_at)
  VALUES (?, ?, ?, toTimestamp(now()));

  -- Email lookup table (for login by email)
  INSERT INTO users_by_email (email, user_id)
  VALUES (?, ?);

  -- Username lookup table (for uniqueness)
  INSERT INTO users_by_username (username, user_id)
  VALUES (?, ?);

APPLY BATCH;

// ✅ All 3 tables updated atomically
// ✅ Can't have orphaned records

Example 2: Sensor Data (Same Partition)

-- Multiple readings from same sensor
BEGIN UNLOGGED BATCH

  INSERT INTO sensor_data (sensor_id, timestamp, temperature)
  VALUES ('sensor-123', now(), 72.5);

  INSERT INTO sensor_data (sensor_id, timestamp, temperature)
  VALUES ('sensor-123', now(), 72.6);

  INSERT INTO sensor_data (sensor_id, timestamp, temperature)
  VALUES ('sensor-123', now(), 72.7);

APPLY BATCH;

// ✅ Same partition = efficient
// ✅ Unlogged = faster
// ✅ Missing one reading isn't critical

✅ BATCH Best Practices

Golden Rules

  1. Use BATCH for correctness, not performance
  2. Keep batches small (5-10 statements max)
  3. Same partition = unlogged BATCH
  4. Cross-partition = logged BATCH (if atomicity needed)
  5. Never batch for bulk inserts
  6. Monitor batch sizes in production
Scenario Recommendation
Denormalized writes (must sync) Logged BATCH
Same partition multiple writes Unlogged BATCH
Bulk inserts (1000s of rows) Individual writes (async)
Performance optimization Don't use BATCH!
Cross-partition (no atomicity need) Individual writes
Advertisement

Google AdSense - Responsive Ad Unit