postgres
Aug 23, 20261 min read
postgres
client-side patterns for postgres (examples use asyncpg). moved here from the python notes.
connection pools
a pool amortizes connection setup and caps concurrent connections. lazily initialize a module-level singleton and hand out connections through a context manager so every use site gets acquire/release right:
_pool: asyncpg.Pool | None = None
async def get_pool() -> asyncpg.Pool:
global _pool
if _pool is None:
_pool = await asyncpg.create_pool(db_url, min_size=2, max_size=10)
return _pool
@asynccontextmanager
async def get_conn() -> AsyncGenerator[asyncpg.Connection, None]:
pool = await get_pool()
async with pool.acquire() as conn:
yield connbatch writes with unnest
unnest() turns parallel arrays into rows, so thousands of inserts become one statement and one round trip — pass one array per column:
await conn.execute(
"""
INSERT INTO follows (follower_id, rkey, subject_id)
SELECT * FROM unnest($1::bigint[], $2::text[], $3::bigint[])
ON CONFLICT (follower_id, rkey) DO UPDATE
SET subject_id = EXCLUDED.subject_id
""",
follower_ids, rkeys, subject_ids,
)ON CONFLICT ... DO UPDATE makes the batch an upsert, so replays are idempotent.
sources
Did you enjoy this article?
Recommend it — Standard Reader surfaces well-loved writing to more readers across the network.