Skip to content

Today I learned

How do I cap a Postgres table by size and delete the oldest rows first?

· updated #Web development #DevOps and tooling

Preview images for share links sat in a bytea column and were never deleted. Refusing new links at a ceiling is worse: the newest links are the ones in fresh posts.

One DELETE with a running sum, newest first, removes every row past the ceiling:

sql
DELETE FROM shares WHERE id IN (
  SELECT id FROM (
    SELECT id,
      sum(octet_length(image)) OVER (ORDER BY created_at DESC, id DESC) AS acc,
      row_number()             OVER (ORDER BY created_at DESC, id DESC) AS nth
    FROM shares
  ) t
  WHERE acc > $1 AND nth > 1   -- $1 = ceiling in bytes; keep the newest row
) RETURNING octet_length(image) AS freed;
  • Trim to 95% of the ceiling, or a full table runs this on every insert.
  • Cache the total: re-read the sum every 10 minutes, add each insert's size in between. octet_length on bytea doesn't decompress, so it's cheap.
  • Add a per-user cap (newest 200 per user_id), or one heavy user evicts everyone else.

Hit this bounding share-image storage in a game backend (1 GB guests, 4 GB players). Window functions docs

The 30-second version

Share LinkedIn Post on X

Related notes

Newsletter

Occasional notes on engineering, game tech, and new tools — no spam, unsubscribe anytime.

Ravy

Engineering manager, founder, and software developer building web platforms, game systems, real-time services, and automation tools. 15 years of shipped work — currently at Gaijin.net.

Get in Touch

Building an MVP, shipping a game feature, or automating a team workflow? Open source or paid — let's talk.

Contact Me
© 2020-2026 XPLOIT FZE. All trademarks, names and logos belong to their respective copyright holders.