CI / changes (push) Successful in 8s
CI / commitlint (push) Has been skipped
CI / openapi (push) Has been skipped
CI / web (push) Successful in 30s
CI / go (push) Failing after 24s
CI / bird2 (push) Has been skipped
CI / release (push) Has been skipped
Updated the PostgreSQL monitoring service to improve handling of `pg_stat_statements` availability. Introduced a new method to check if the extension is queryable and updated the response structure to include availability status and hints. Enhanced the documentation to clarify the requirements for enabling `pg_stat_statements`. Adjusted related components to reflect these changes, ensuring better user feedback in the monitoring interface.
113 lines
4.0 KiB
Markdown
113 lines
4.0 KiB
Markdown
# Диагностика схемы PostgreSQL (EvoBGP)
|
|
|
|
Runbook для оценки объёма БД и узких мест **перед** и **после** миграций оптимизации схемы. Выполнять на staging или production read-only сессией.
|
|
|
|
## Подключение
|
|
|
|
```bash
|
|
psql "$EVOBGP_DATABASE_URL"
|
|
```
|
|
|
|
## HTTP API (панель / мониторинг)
|
|
|
|
При подключённом PostgreSQL control plane отдаёт instance-level метрики (роль **viewer+**):
|
|
|
|
- `GET /v1/monitoring/postgres/overview` — подключения, TPS, cache hit, размер БД
|
|
- `GET /v1/monitoring/postgres/queries` — top queries (`pg_stat_statements`, если extension включён)
|
|
- `GET /v1/monitoring/postgres/locks`, `/tables`, `/recommendations`
|
|
- `GET /v1/monitoring/correlation?window=60` — корреляция refresh jobs и cache hit
|
|
|
|
Обслуживание (**operator**, async `202` + `job_id`): `POST /v1/postgres/vacuum`, `vacuum-analyze`, `analyze`, `reindex`, `cleanup`; журнал `GET /v1/postgres/maintenance/logs`.
|
|
|
|
CLI на CP: `evobgp-api db report|vacuum|analyze|cleanup` (см. `internal/dbcli`).
|
|
|
|
Миграция `000023` создаёт `pg_stat_statements`; для сбора статистики **обязательно** preload и перезапуск Postgres:
|
|
|
|
```text
|
|
# postgresql.conf или command в compose
|
|
shared_preload_libraries = 'pg_stat_statements'
|
|
```
|
|
|
|
После изменения — restart контейнера/сервиса Postgres. Без этого API `/v1/monitoring/postgres/queries` вернёт пустой список (`statements_available: false`), без 5xx.
|
|
|
|
## 1. Размеры таблиц и индексов
|
|
|
|
```sql
|
|
SELECT relname,
|
|
pg_size_pretty(pg_total_relation_size(relid)) AS total,
|
|
pg_size_pretty(pg_relation_size(relid)) AS heap,
|
|
pg_size_pretty(pg_indexes_size(relid)) AS indexes
|
|
FROM pg_catalog.pg_statio_user_tables
|
|
ORDER BY pg_total_relation_size(relid) DESC;
|
|
```
|
|
|
|
**Ожидание:** лидеры — `revision_materialized_prefix`, `config_revision` (TOAST от preview), JSONB-кэши.
|
|
|
|
## 2. Seq scan (горячие таблицы)
|
|
|
|
```sql
|
|
SELECT schemaname, relname, seq_scan, seq_tup_read, idx_scan
|
|
FROM pg_stat_user_tables
|
|
WHERE schemaname = 'public'
|
|
ORDER BY seq_tup_read DESC;
|
|
```
|
|
|
|
Сброс статистики после деплоя: `SELECT pg_stat_reset();` (только осознанно, теряется baseline).
|
|
|
|
## 3. Неиспользуемые индексы
|
|
|
|
```sql
|
|
SELECT indexrelname, idx_scan, pg_size_pretty(pg_relation_size(indexrelid)) AS size
|
|
FROM pg_stat_user_indexes
|
|
WHERE schemaname = 'public' AND idx_scan = 0
|
|
ORDER BY pg_relation_size(indexrelid) DESC;
|
|
```
|
|
|
|
## 4. Дубликаты в materialized prefixes
|
|
|
|
Перед UNIQUE `(revision_id, prefix, community_id, source)`:
|
|
|
|
```sql
|
|
SELECT revision_id, prefix, community_id, source, COUNT(*) AS n
|
|
FROM revision_materialized_prefix
|
|
GROUP BY 1, 2, 3, 4
|
|
HAVING COUNT(*) > 1
|
|
LIMIT 20;
|
|
```
|
|
|
|
## 5. Шаблон отчёта staging
|
|
|
|
| Метрика | До | После | Дата |
|
|
|---------|-----|-------|------|
|
|
| `revision_materialized_prefix` total | | | |
|
|
| `config_revision` total | | | |
|
|
| `module_prefix_snapshot` total | | | |
|
|
| `asn_prefix_cache` total | | | |
|
|
| Top seq_scan table | | | |
|
|
| Unused indexes (count) | | | |
|
|
|
|
## 6. EXPLAIN для типовых запросов
|
|
|
|
```sql
|
|
-- Список префиксов ревизии (keyset)
|
|
EXPLAIN (ANALYZE, BUFFERS)
|
|
SELECT prefix::text, community_id::text, source
|
|
FROM revision_materialized_prefix
|
|
WHERE revision_id = '<revision-uuid>'::uuid
|
|
ORDER BY id
|
|
LIMIT 51;
|
|
|
|
-- Diff added (anti-join)
|
|
EXPLAIN (ANALYZE, BUFFERS)
|
|
SELECT b.prefix::text
|
|
FROM revision_materialized_prefix b
|
|
LEFT JOIN revision_materialized_prefix a
|
|
ON a.revision_id = '<rev-a>'::uuid AND a.prefix = b.prefix
|
|
WHERE b.revision_id = '<rev-b>'::uuid
|
|
AND a.prefix IS NULL
|
|
ORDER BY b.prefix
|
|
LIMIT 5001;
|
|
```
|
|
|
|
Цель: Index Scan / Bitmap Index Scan по `(revision_id, …)`, без Seq Scan на больших таблицах.
|