Skip to content

Commit aafe55b

Browse files
committed
create/test db-diagnose skill
1 parent 0b54c3f commit aafe55b

1 file changed

Lines changed: 142 additions & 0 deletions

File tree

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
---
2+
name: db-diagnose
3+
description: Diagnose database issues like TOAST bloat, idle transactions, dead tuples, and disk usage on the Subsquid Cloud PostgreSQL database. Use when the database is slow, bloated, unresponsive, or running out of space.
4+
---
5+
6+
# Database Diagnostics
7+
8+
You are diagnosing database issues for the origin-squid project deployed on Subsquid Cloud.
9+
10+
## Step 1: Get Database Credentials
11+
12+
Run this to get the Subsquid Cloud database connection info:
13+
14+
```bash
15+
npx sqd view -o origin -n origin-squid -t prod --json
16+
```
17+
18+
Parse the JSON output to extract the postgres connection params from `addons.postgres.connections`. Prefer the read/write connection (not read-only) since some diagnostics need it.
19+
20+
Construct a `psql` connection string or use individual params. For running queries use:
21+
22+
```bash
23+
PGPASSWORD=<password> psql -h <host> -p <port> -U <user> -d <database>
24+
```
25+
26+
## Step 2: Run Diagnostics
27+
28+
Run ALL of these diagnostic queries and report the results:
29+
30+
### TOAST Table Sizes (the most common issue)
31+
```sql
32+
SELECT
33+
n.nspname AS schema_name,
34+
c.relname AS table_name,
35+
t.relname AS toast_table,
36+
pg_size_pretty(pg_relation_size(t.oid)) AS toast_size,
37+
pg_size_pretty(pg_relation_size(c.oid)) AS main_size,
38+
pg_size_pretty(pg_total_relation_size(c.oid)) AS total_size
39+
FROM pg_class c
40+
JOIN pg_class t ON t.oid = c.reltoastrelid
41+
JOIN pg_namespace n ON n.oid = c.relnamespace
42+
WHERE t.relkind = 't'
43+
ORDER BY pg_relation_size(t.oid) DESC
44+
LIMIT 20;
45+
```
46+
47+
### Idle/Long-Running Transactions (block VACUUM from reclaiming space)
48+
```sql
49+
SELECT pid, state, now() - xact_start AS tx_age,
50+
now() - query_start AS query_age,
51+
left(query, 150) AS query
52+
FROM pg_stat_activity
53+
WHERE xact_start IS NOT NULL
54+
ORDER BY xact_start ASC
55+
LIMIT 20;
56+
```
57+
58+
### Dead Tuple Counts (tables needing VACUUM)
59+
```sql
60+
SELECT schemaname, relname,
61+
n_dead_tup, n_live_tup,
62+
round(n_dead_tup::numeric / greatest(n_live_tup, 1) * 100, 1) AS dead_pct,
63+
last_vacuum, last_autovacuum
64+
FROM pg_stat_user_tables
65+
WHERE n_dead_tup > 10000
66+
ORDER BY n_dead_tup DESC
67+
LIMIT 20;
68+
```
69+
70+
### VACUUM Horizon (if old, something is holding it back)
71+
```sql
72+
SELECT datname, datfrozenxid, age(datfrozenxid) AS xid_age
73+
FROM pg_database WHERE datname = current_database();
74+
```
75+
76+
### Overall Disk Usage
77+
```sql
78+
SELECT
79+
n.nspname AS schema_name,
80+
c.relname AS table_name,
81+
pg_size_pretty(pg_total_relation_size(c.oid)) AS total_size,
82+
pg_size_pretty(pg_relation_size(c.oid)) AS table_size,
83+
pg_size_pretty(pg_indexes_size(c.oid)) AS index_size
84+
FROM pg_class c
85+
JOIN pg_namespace n ON n.oid = c.relnamespace
86+
WHERE c.relkind = 'r'
87+
AND n.nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
88+
ORDER BY pg_total_relation_size(c.oid) DESC
89+
LIMIT 20;
90+
```
91+
92+
### Active Locks
93+
```sql
94+
SELECT l.pid, l.mode, l.granted, c.relname, a.state, left(a.query, 100) AS query
95+
FROM pg_locks l
96+
JOIN pg_class c ON c.oid = l.relation
97+
JOIN pg_stat_activity a ON a.pid = l.pid
98+
WHERE NOT l.granted OR l.mode LIKE '%Exclusive%'
99+
ORDER BY l.granted, c.relname
100+
LIMIT 20;
101+
```
102+
103+
### Database Size
104+
```sql
105+
SELECT pg_size_pretty(pg_database_size(current_database())) AS db_size;
106+
```
107+
108+
## Step 3: Analyze and Recommend
109+
110+
Based on the results, identify:
111+
112+
1. **Root cause**: What is causing the issue (idle transactions, TOAST bloat, missing vacuums, etc.)
113+
2. **Immediate fix**: Commands to run right now (e.g., `pg_terminate_backend(pid)`, `VACUUM FULL`)
114+
3. **Prevention**: What should be done to prevent recurrence
115+
116+
### Common Fixes
117+
118+
**Kill idle-in-transaction sessions:**
119+
```sql
120+
SELECT pg_terminate_backend(pid)
121+
FROM pg_stat_activity
122+
WHERE state = 'idle in transaction'
123+
AND now() - xact_start > interval '2 minutes';
124+
```
125+
126+
**VACUUM FULL a bloated table** (locks table, use with care):
127+
```sql
128+
VACUUM FULL VERBOSE "schema_name"."table_name";
129+
```
130+
131+
**Regular VACUUM** (less disruptive, doesn't reclaim TOAST as well):
132+
```sql
133+
VACUUM VERBOSE "schema_name"."table_name";
134+
```
135+
136+
## Important Notes
137+
138+
- `VACUUM FULL` takes an ACCESS EXCLUSIVE lock — all queries on that table will block until it finishes. Warn the user before running.
139+
- Always ask the user before running destructive operations (killing sessions, VACUUM FULL).
140+
- The mainnet processor has a built-in TOAST vacuum monitor (`src/utils/toast-vacuum.ts`) that checks every 30 minutes and auto-vacuums tables with TOAST > 1GB.
141+
- Session timeouts are configured at the database level: `idle_in_transaction_session_timeout = 2min`, `idle_session_timeout = 5min`.
142+
- Use `$ARGUMENTS` for any specific table or issue the user wants to investigate.

0 commit comments

Comments
 (0)