---
title: "Spread writes that all land on one row · Agent Wranglers"
url: https://agentwranglers.se/playbook/scaling/growing-the-database/hot-rows
id: SCL-40
level: Recommended
updated: 2026-10-27
build: a2a6bdfed830
tokens: 1083
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Spread writes that all land on one row

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Growing the database](https://agentwranglers.se/playbook/scaling/growing-the-database.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-27.

- ID: SCL-40
- Level: Recommended
- Chapter: [Growing the database](https://agentwranglers.se/playbook/scaling/growing-the-database.md)
- Rule: When most requests update one row or key, such as a view counter, split it into several rows or batch the updates. Writers must not queue on one lock.
- Check: Run the load test at the planned peak on staging, with PostgreSQL's `log_lock_waits = on` and `deadlock_timeout = 100ms` or the same setting in your database. The log shows no lock wait on a counter or total table.
- How: An update holds its row lock until the transaction ends, so a counter that every request bumps makes those requests wait in line. The same happens to one hot key in a cache cluster, since one key lives on one shard. Split the counter into a fixed number of slots, such as 16, and add one to a random slot. Read the total as the sum of the slots. Or add the counts up in memory or in [a shared store](https://agentwranglers.se/playbook/scaling/stateless-app-servers/shared-locks-and-counters.md) and write them every few seconds. Keep exact checks, such as stock that must not go below zero, in one guarded update, as [Wrap multi-step changes in a transaction](https://agentwranglers.se/playbook/data/transactions-and-concurrency/transactions.md) says. Run the load as [Test load against a budget](https://agentwranglers.se/playbook/testing/performance-tests/load-tests.md) describes.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
const COUNTER_SLOTS = 16;

export async function countView(db, pageId) {
  const slot = Math.floor(Math.random() * COUNTER_SLOTS);
  await db.query(
    'INSERT INTO page_views (page_id, slot, views) VALUES ($1, $2, 1) ON CONFLICT (page_id, slot) DO UPDATE SET views = page_views.views + 1',
    [pageId, slot],
  );
}
```

### Python example

```python
import random

COUNTER_SLOTS = 16

def count_view(cursor, page_id: int) -> None:
    cursor.execute(
        "INSERT INTO page_views (page_id, slot, views) VALUES (%s, %s, 1) "
        "ON CONFLICT (page_id, slot) DO UPDATE SET views = page_views.views + 1",
        (page_id, random.randrange(COUNTER_SLOTS)),
    )

def total_views(cursor, page_id: int) -> int:
    cursor.execute("SELECT COALESCE(SUM(views), 0) FROM page_views WHERE page_id = %s", (page_id,))
    return cursor.fetchone()[0]
```

## Sources

- [PostgreSQL, Error reporting and logging (log_lock_waits)](https://www.postgresql.org/docs/current/runtime-config-logging.html)

## Related rules

- SCL-42 [Spread the reads of one hot cache key](https://agentwranglers.se/playbook/scaling/caching/hot-cache-keys.md) in Scaling
- SCL-8 [Keep locks and counters in a shared store](https://agentwranglers.se/playbook/scaling/stateless-app-servers/shared-locks-and-counters.md) in Scaling
- DAT-14 [Wrap multi-step changes in a transaction](https://agentwranglers.se/playbook/data/transactions-and-concurrency/transactions.md) in Data and databases
- TST-36 [Test load against a budget](https://agentwranglers.se/playbook/testing/performance-tests/load-tests.md) in Testing

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/scaling/growing-the-database/hot-rows">Agent Wranglers scaling playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Change large tables in small batches](https://agentwranglers.se/playbook/scaling/growing-the-database/small-batches.md)
- Next: [Splitting one database across servers too early](https://agentwranglers.se/playbook/scaling/growing-the-database/early-sharding.md)
- [Growing the database](https://agentwranglers.se/playbook/scaling/growing-the-database.md)
