---
title: "Load related rows in one query · Agent Wranglers"
url: https://agentwranglers.se/playbook/data/queries-and-indexes/no-n-plus-one
updated: 2026-10-20
licence: "All rights reserved"
---

# Load related rows in one query

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Required
- Chapter: [Queries and indexes](https://agentwranglers.se/playbook/data/queries-and-indexes)
- Rule: Never run one query per item in a list. Load related rows together with a join or one `IN` query.
- How: Watch for loops that call the database, often hidden behind lazy loading in an ORM. Use the ORM's eager loading, a join, or one query with `WHERE id = ANY($1)`. Count queries per request in development.
- Check: A test loads a list with 5 items and with 50, counting the queries through the driver's query hook or log. Both counts are equal.

Example:

```js
// Bad: 1 query for orders, then 1 per order
for (const order of orders) order.customer = await db.one('SELECT * FROM customers WHERE id = $1', [order.customer_id]);
// Good: 2 queries in total
const customers = await db.many('SELECT id, name FROM customers WHERE id = ANY($1)', [orders.map(o => o.customer_id)]);
```

```python
# Good in Python: 2 queries in total
customer_ids = [order.customer_id for order in orders]
cursor.execute("SELECT id, name FROM customers WHERE id = ANY(%s)", (customer_ids,))
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers data playbook: https://agentwranglers.se/playbook/data/queries-and-indexes/no-n-plus-one`.

- Previous: [Read the query plan](https://agentwranglers.se/playbook/data/queries-and-indexes/query-plans)
- Next: [Select only the columns you use](https://agentwranglers.se/playbook/data/queries-and-indexes/select-columns)
- [Queries and indexes](https://agentwranglers.se/playbook/data/queries-and-indexes)
