Azpg config tuning
Skill lestermarch/postgres-ai-experts/skills/azpg-config-tuning
Composable AI agents and skills for operating Azure Database for PostgreSQL Flexible Server - PostgreSQL can be used for everything.
npx -y skills add lestermarch/postgres-ai-experts --skill azpg-config-tuningAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
3 things to look at
- 20 days oldThe repository was created 20 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Tune server parameters on Azure Database for PostgreSQL Flexible Server — memory (work_mem, maintenance_work_mem, shared_buffers, effective_cache_size), autovacuum aggressiveness, max_connections, statement/lock timeouts, and connection pooling with the built-in PgBouncer. Use this skill whenever the task involves changing a Postgres server parameter, "work_mem", "shared_buffers", "max_connections", autovacuum tuning, connection pooling / PgBouncer, statement_timeout, "az postgres flexible-server parameter set", a parameter that needs a restart, or "how do I make my server use more memory / handle more connections?" on Flexible Server. For finding WHICH query or table needs tuning first hand off to azpg-stat-diagnostics or azpg-explain-analyze; this skill changes the knobs.
SKILL.md
9.0 KB, as published. Nobody here has run it
Tuning server parameters on Azure Database for PostgreSQL Flexible Server
On Flexible Server you do not edit postgresql.conf and you cannot ALTER SYSTEM most parameters — the control plane owns the config. You change parameters
through the Azure surface: az postgres flexible-server parameter set, the portal,
Bicep/Terraform, or the REST API. Postgres then applies them either immediately
(dynamic) or on the next restart (static).
This skill is read-write and explicit. Reading a parameter's current value and
listing which parameters need a restart change nothing and are auto-runnable.
Persisting a new value with parameter set is the mutation — for a static
parameter it can trigger a server restart (a brief outage), so it is guarded and
requires an explicit go-ahead.
Live instance context (dynamic injection)
Inject the real config so tuning advice matches the actual tier and current values, not defaults:
- Tier / memory (sizing drives every memory parameter):
!
az postgres flexible-server show --resource-group "$RG" --name "$SERVER" --query "{sku:sku.name, tier:sku.tier, storageGB:storage.storageSizeGb, ha:highAvailability.mode}" -o tsv - Key memory + connection settings right now (unit-aware, shows source):
!
psql "$PGCONN" -tAc "SELECT name, setting, unit, source, pending_restart FROM pg_settings WHERE name IN ('shared_buffers','work_mem','maintenance_work_mem','effective_cache_size','max_connections','max_worker_processes') ORDER BY name;" - Anything staged but awaiting a restart:
!
psql "$PGCONN" -tAc "SELECT name, setting FROM pg_settings WHERE pending_restart;" - Is the built-in pooler on?
!
az postgres flexible-server parameter show --resource-group "$RG" --server-name "$SERVER" --name pgbouncer.enabled --query value -o tsv
pending_restart = t means a static change is staged and the value is not live
yet — the server must be restarted for it to take effect.
When to use this skill
- "Queries spill to disk / sorts are slow" → raise
work_mem(carefully — it's per-operation, not per-connection). - "Index builds and VACUUM are slow" → raise
maintenance_work_mem. - "Autovacuum can't keep up / bloat is growing" → make autovacuum more aggressive.
- "Too many connections" errors → pool with PgBouncer before raising
max_connections. - "I need to change
<parameter>on the server." - Setting safe guardrails:
statement_timeout,lock_timeout,idle_in_transaction_session_timeout.
Use azpg-stat-diagnostics / azpg-explain-analyze first to prove which
knob matters — tuning blind wastes a restart.
Decision flow
- Identify the symptom precisely (read · auto) — ideally from
azpg-stat-diagnostics. "Slow" is not a tuning target; "sorts spilling to disk under concurrency" is. - Read the current value and its context (read · auto) —
scripts/inspect_params.sqlshowssetting,unit,context(postmaster/sighup/user),source, andpending_restart.contexttells you whether a restart is required (postmaster= static/restart). - Test session-scoped first where possible (read · auto, non-persistent) —
for
work_mem,SET work_mem='64MB';then re-EXPLAIN (ANALYZE)in the same session. This proves the value helps without touching the server and affects only your session. - Persist the change (write · guarded · explicit) — once proven, apply it
server-wide with
scripts/set_parameter.sh(previews theazcommand, warns if a restart is required,--dry-runby default until you pass--apply). - Restart only if the parameter is static (write · guarded · explicit) — the script tells you; a restart is a brief outage (HA fails over; single-server blips). Never restart silently.
- Verify (read · auto) — re-read
pg_settings; confirmpending_restartcleared andsource = 'user-override'.
Which parameter for which symptom
| Symptom (from diagnostics) | Parameter | Restart? | Notes |
|---|---|---|---|
| Sorts/hashes spill to disk | work_mem | No (dynamic) | Per operation per connection — total = work_mem × concurrent sorts. Raise gradually. |
Slow CREATE INDEX / VACUUM | maintenance_work_mem | No | Only a few run at once, so it can be large. |
| Low cache hit ratio, RAM to spare | effective_cache_size | No | A planner hint (no RAM reserved); set ≈ 50–75% of memory so index scans are costed correctly. |
| Autovacuum lagging, bloat rising | autovacuum_vacuum_scale_factor, autovacuum_vacuum_cost_limit, autovacuum_naptime | No | Lower scale factor = vacuum sooner; higher cost limit = vacuum faster. |
| "too many connections" | PgBouncer (pgbouncer.enabled, pgbouncer.pool_mode) | See note | Pool before raising max_connections. |
| Runaway queries / stuck idle txns | statement_timeout, idle_in_transaction_session_timeout | No | Cheap safety rails. |
max_connections, shared_buffers | — | Yes (static) | context = postmaster; Azure sizes these to the tier — change only with reason. |
Connection pooling (PgBouncer) — prefer over raising max_connections
Each Postgres connection costs memory and a backend process; thousands of idle app connections starve real work. Flexible Server ships built-in PgBouncer on port 6432 (same hostname, port 6432 instead of 5432). Enable and shape it with parameters, then point the app at 6432:
pgbouncer.enabled = truepgbouncer.pool_mode = transaction(highest reuse; app must not rely on session-level state / session-scopedSET, advisory locks, etc.)pgbouncer.default_pool_size,pgbouncer.max_client_conn— size the pool.
Raising max_connections is a static change (restart) and multiplies memory
pressure; pooling usually solves "too many connections" without either cost.
Safety protocol
- Prove the knob matters first. A restart or a fleet-wide
work_membump without evidence is how you turn one slow query into an OOM. Come fromazpg-stat-diagnostics/azpg-explain-analyze. - Session-scope before server-scope. For user-context parameters,
SETin one session and re-measure — zero blast radius — before persisting. set_parameter.shis dry-run by default. It prints the current value, theaz … parameter setit would run, and whether the parameter is static (restart). It changes nothing until--apply.- Restart is never implicit. Static parameters stage as
pending_restart; the restart is a separate, explicit, announced step (it is a brief outage). work_memis a trap. It's per sort/hash per connection.64MB× hundreds of connections each doing multiple sorts can exceed server memory. Multiply it out againstmax_connectionsbefore applying.- Don't fight Azure's tier defaults blindly.
shared_buffers,max_connections, and friends are sized to the SKU; the right fix for "not enough memory" is often a bigger tier, not an override that destabilises the box.
Bundled files
reference.md— parameter-by-parameter guidance (memory model, autovacuum math, timeouts), the dynamic-vs-static rule viapg_settings.context, and how Azure derives defaults from the tier.azure-constraints.md— noALTER SYSTEM/postgresql.conf; parameters Azure locks; static-parameter restart semantics and HA failover behaviour; PgBouncer specifics;--source user-overrideto revert.scripts/inspect_params.sql— read-only dump of the tuning-relevantpg_settingsrows with unit, context, source, and pending_restart.scripts/set_parameter.sh— guarded write; previews theaz parameter set, flags static/restart parameters,--dry-rundefault,--applyto execute.scripts/README.md— script catalog + safety class.examples/tuning_work_mem.md— worked end-to-end: prove with sessionSET, do the memory arithmetic, persist safely.EVALUATION.md— trigger prompts, expected behaviour, conventions self-review.