rust.n_plus_one
Performance
High
Detects N+1 query patterns where database queries are executed inside loops.
Why It Matters
Section titled “Why It Matters”N+1 queries:
- Kill performance — 100 items = 101 queries
- Overwhelm databases — Connection pool exhaustion
- Increase latency — Linear time complexity
Example
Section titled “Example”// ❌ Before (N+1 query pattern)async fn get_users_with_orders(db: &Pool) -> Vec<UserWithOrders> { let users = sqlx::query_as!(User, "SELECT * FROM users") .fetch_all(db).await?;
let mut result = Vec::new(); for user in users { let orders = sqlx::query_as!(Order, "SELECT * FROM orders WHERE user_id = ?", user.id) .fetch_all(db).await?; // Query per user! result.push(UserWithOrders { user, orders }); } result}// ✅ After (batch query with JOIN)async fn get_users_with_orders(db: &Pool) -> Vec<UserWithOrders> { let rows = sqlx::query!( "SELECT u.*, o.* FROM users u LEFT JOIN orders o ON o.user_id = u.id") .fetch_all(db).await?;
// Group by user rows.into_iter() .group_by(|r| r.user_id) .map(|(_, group)| /* build UserWithOrders */) .collect()}What Unfault Detects
Section titled “What Unfault Detects”- SQLx queries inside loops
- Diesel queries per iteration
- Missing eager loading patterns
Auto-Fix
Section titled “Auto-Fix”Unfault suggests JOIN queries or batch fetching strategies.