Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified diagrams/erdiagram_targetdb_latest.pdf
Binary file not shown.
230 changes: 230 additions & 0 deletions docs/examples/queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,233 @@ AND EXISTS (
AND t.proposal_id = 'S25A-039'
);
```

---

## PostgreSQL Troubleshooting

### Running Processes

#### Show all active processes

```sql
/* Show all currently connected processes */
SELECT
pid,
usename,
application_name,
client_addr,
state,
wait_event_type,
wait_event,
query_start,
now() - query_start AS duration,
query
FROM pg_stat_activity
WHERE pid <> pg_backend_pid()
ORDER BY query_start;
```

#### Show processes for a specific database

```sql
/* Show processes for a specific database */
SELECT
pid,
usename,
state,
wait_event_type,
wait_event,
now() - query_start AS duration,
query
FROM pg_stat_activity
WHERE datname = 'your_database_name'
AND pid <> pg_backend_pid()
ORDER BY query_start;
```

#### Show only active queries

```sql
/* Show only currently running queries */
SELECT pid, usename, now() - query_start AS duration, query
FROM pg_stat_activity
WHERE state = 'active'
AND pid <> pg_backend_pid()
ORDER BY duration DESC;
```

#### Show long-running queries

```sql
/* Show queries that have been running for more than 5 minutes */
SELECT pid, usename, state, now() - query_start AS duration, query
FROM pg_stat_activity
WHERE now() - query_start > interval '5 minutes'
AND state <> 'idle'
AND pid <> pg_backend_pid()
ORDER BY duration DESC;
```

#### Show idle-in-transaction processes

```sql
/* Show processes in 'idle in transaction' state (common cause of locks) */
SELECT pid, usename, state, now() - query_start AS duration, query
FROM pg_stat_activity
WHERE state IN ('idle in transaction', 'idle in transaction (aborted)')
ORDER BY duration DESC;
```

#### Count connections by user and state

```sql
/* Count connections grouped by user and state */
SELECT count(*) AS cnt, usename, state
FROM pg_stat_activity
GROUP BY usename, state
ORDER BY cnt DESC;
```

---

### Locks

#### Show lock-waiting processes

```sql
/* Show processes waiting on locks and the processes blocking them */
SELECT
blocking.pid AS blocking_pid,
blocking.state AS blocking_state,
left(blocking.query, 80) AS blocking_query,
blocked.pid AS blocked_pid,
blocked.state AS blocked_state,
blocked.wait_event,
left(blocked.query, 80) AS blocked_query
FROM pg_stat_activity blocked
JOIN pg_stat_activity blocking
ON blocking.pid = ANY(pg_blocking_pids(blocked.pid))
ORDER BY blocking.pid;
```

#### Show blockers for a specific query

```sql
/* Show processes blocking a specific query (e.g., ALTER TABLE) */
SELECT
blocking.pid AS blocking_pid,
blocking.state AS blocking_state,
left(blocking.query, 80) AS blocking_query,
blocked.pid AS blocked_pid,
blocked.state AS blocked_state,
blocked.wait_event
FROM pg_stat_activity blocked
JOIN pg_stat_activity blocking
ON blocking.pid = ANY(pg_blocking_pids(blocked.pid))
WHERE blocked.query LIKE 'ALTER TABLE%';
```

---

### Terminating Processes

#### Cancel a query (keep connection)

```sql
/* Cancel the query only; the connection is preserved */
SELECT pg_cancel_backend(<pid>);
```

#### Force-terminate a process

```sql
/* Terminate the connection entirely; use when pg_cancel_backend has no effect */
SELECT pg_terminate_backend(<pid>);
```

#### Bulk-terminate idle-in-transaction processes

```sql
/* Terminate all idle-in-transaction processes older than 1 hour */
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state IN ('idle in transaction', 'idle in transaction (aborted)')
AND now() - query_start > interval '1 hour'
AND pid <> pg_backend_pid();
```

#### Bulk-terminate stale idle connections

```sql
/* Terminate all idle connections older than 1 day */
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
AND now() - state_change > interval '1 day'
AND pid <> pg_backend_pid();
```

---

### Table and Index Information

#### Check table sizes

```sql
/* Check the size of specific tables (including indexes) */
SELECT
pg_size_pretty(pg_total_relation_size('target')) AS target_size,
pg_size_pretty(pg_total_relation_size('fluxstd')) AS fluxstd_size;
```

#### List largest tables in the database

```sql
/* List tables ordered by total size */
SELECT
relname AS table_name,
pg_size_pretty(pg_total_relation_size(relid)) AS total_size
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 20;
```

---

### DDL Operations on Large Tables

#### Safely add a FOREIGN KEY constraint

```sql
/* Split into NOT VALID + VALIDATE to minimise lock duration */

-- Step 1: Add the constraint without validation (short lock)
ALTER TABLE target
ADD CONSTRAINT target_filter_u_fkey
FOREIGN KEY (filter_u) REFERENCES filter_name(filter_name)
NOT VALID;

-- Step 2: Validate the constraint (uses ShareUpdateExclusiveLock; does not block reads/writes)
ALTER TABLE target VALIDATE CONSTRAINT target_filter_u_fkey;
```

#### Safely create or drop an index

```sql
/* Use CONCURRENTLY to avoid blocking other queries */

-- Create
CREATE INDEX CONCURRENTLY idx_target_ra ON target(ra);

-- Drop
DROP INDEX CONCURRENTLY idx_target_ra;
```

#### Set timeouts during migrations

```sql
/* Prevent migrations from hanging indefinitely on lock acquisition */
SET lock_timeout = '5s'; -- Fail immediately if the lock cannot be acquired within 5 s
SET statement_timeout = '0'; -- No time limit on the statement itself
```
4 changes: 2 additions & 2 deletions docs/tbls/public.fluxstd.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,10 @@
| ---- | ---------- |
| fluxstd_pkey | CREATE UNIQUE INDEX fluxstd_pkey ON public.fluxstd USING btree (fluxstd_id) |
| uq_obj_id_input_catalog_id_version | CREATE UNIQUE INDEX uq_obj_id_input_catalog_id_version ON public.fluxstd USING btree (obj_id, input_catalog_id, version) |
| fluxstd_q3c_ang2ipix_idx | CREATE INDEX fluxstd_q3c_ang2ipix_idx ON public.fluxstd USING btree (q3c_ang2ipix(ra, "dec")) |
| ix_fluxstd_input_catalog_fluxstdid | CREATE INDEX ix_fluxstd_input_catalog_fluxstdid ON public.fluxstd USING btree (input_catalog_id, fluxstd_id) |
| ix_fluxstd_version_fluxstdid | CREATE INDEX ix_fluxstd_version_fluxstdid ON public.fluxstd USING btree (version, fluxstd_id) |
| ix_fluxstd_version | CREATE INDEX ix_fluxstd_version ON public.fluxstd USING btree (version) |
| ix_fluxstd_input_catalog_fluxstdid | CREATE INDEX ix_fluxstd_input_catalog_fluxstdid ON public.fluxstd USING btree (input_catalog_id, fluxstd_id) |
| fluxstd_q3c_ang2ipix_idx | CREATE INDEX fluxstd_q3c_ang2ipix_idx ON public.fluxstd USING btree (q3c_ang2ipix(ra, "dec")) |

## Relations

Expand Down
2 changes: 1 addition & 1 deletion docs/tbls/public.sky.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
| ---- | ---------- |
| sky_pkey | CREATE UNIQUE INDEX sky_pkey ON public.sky USING btree (sky_id) |
| sky_obj_id_input_catalog_id_version_key | CREATE UNIQUE INDEX sky_obj_id_input_catalog_id_version_key ON public.sky USING btree (obj_id, input_catalog_id, version) |
| sky_q3c_ang2ipix_idx | CREATE INDEX sky_q3c_ang2ipix_idx ON public.sky USING btree (q3c_ang2ipix(ra, "dec")) |
| ix_sky_input_catalog_id | CREATE INDEX ix_sky_input_catalog_id ON public.sky USING btree (input_catalog_id) |
| sky_q3c_ang2ipix_idx | CREATE INDEX sky_q3c_ang2ipix_idx ON public.sky USING btree (q3c_ang2ipix(ra, "dec")) |
| ix_sky_version | CREATE INDEX ix_sky_version ON public.sky USING btree (version) |

## Relations
Expand Down