Taufiq Septryana
performance kodi

In-Memory Filtering Is Not N+1

Loading data into memory and filtering with JavaScript is not the N+1 query problem. The confusion is common but important to clarify.

What N+1 Actually Is

The N+1 query problem requires database queries inside a loop:

// ❌ N+1: Query inside loop
const users = await db.select().from(users); // 1 query

for (const user of users) {
  const orders = await db.select().from(orders)
    .where(eq(orders.userId, user.id)); // N queries!
}
// Total: 1 + N queries (hence "N+1")

What Is NOT N+1

Loading data once and filtering in memory:

// ✅ NOT N+1: One query, in-memory filtering
const rules = await db
  .select()
  .from(categoryRules)
  .where(eq(categoryRules.userId, userId));

// JavaScript loop - zero DB queries
for (const rule of rules) {
  if (evaluateRule(rule, transaction)) {
    return rule;
  }
}
// Total: 1 query total

The Comparison

PatternQuery CountIssue
N+11 + NDatabase overload
In-memory filtering1Memory usage (if data is huge)

When In-Memory Filtering Makes Sense

  • Rules/categories fit in memory comfortably
  • Complex evaluation logic that’s hard to express in SQL
  • Need to avoid repeated round-trips to database

When to Avoid

  • Dataset is unbounded (could load thousands of rows)
  • Simple filtering that SQL handles better
  • Memory-constrained environments

The Real Issue With Unbounded Loading

If a user has 10,000 rules, loading them all into memory is a memory usage problem, not an N+1 problem. Consider:

  • Pagination
  • Database-level filtering for simple conditions
  • Caching strategies

References