Course contentsShow
← Node.js
Lesson 1340 of 1,98012. Caching Strategies and Application SpeedFree lesson

Efficient Key Scanning and Batch Operations

You will perform high-performance batch operations to reduce the number of network round-trips.

In this lesson, you will learn how to optimize your data retrieval and mutation patterns by using batching and cursor-based scanning to slash the latency costs of network round-trips.

The Problem: The Latency Tax

Every time your Node.js application communicates with a cache like Redis, you incur the cost of a network round-trip. If you need to retrieve 100 individual keys, executing 100 GET commands creates a "chatty" application. This consumes excessive CPU cycles on both the application and the cache server, eventually bottlenecking your throughput.

Batch Operations: Reducing Round-trips

The most immediate way to improve performance is to group operations. Instead of waiting for each individual request to complete, you should use pipelining or bulk commands like MGET or MSET. By sending a single array of keys to the cache, you collapse 100 network packets into one, significantly reducing the "idle time" your Node.js event loop spends waiting for I/O.

// Instead of 100 individual calls, use MGET
const keys = ['user:1', 'user:2', 'user:3', /* ... */];
const values = await redis.mget(keys);

Efficient Key Scanning: Avoiding KEYS *

Often, we need to perform maintenance or mass updates, which leads developers to use the KEYS command. Never do this in production. The KEYS command is O(N) and blocks the entire Redis event loop while it searches, causing a total application freeze.

Instead, use SCAN. The SCAN command allows you to iterate through keyspace in small, incremental batches using a cursor. It provides a non-blocking way to find subsets of keys without stalling your database.

let cursor = '0';
do {
  // SCAN returns the next cursor and a batch of matching keys
  const reply = await redis.scan(cursor, 'MATCH', 'session:*', 'COUNT', 100);
  cursor = reply[0];
  const keys = reply[1];
  
  if (keys.length > 0) {
    await redis.del(keys); // Batch delete the found keys
  }
} while (cursor !== '0');

By combining cursor-based scanning with bulk deletion or updates, you maintain high application responsiveness even when performing large-scale cache maintenance.

Key Takeaway: Batch operations replace multiple individual round-trips with a single network request, while cursor-based scanning keeps your event loop free by replacing blocking global searches with incremental, non-destructive iterations.