senior
Как мониторить производительность PostgreSQL?
PostgreSQL предоставляет богатый набор системных представлений (pg_stat_*) и расширений для мониторинга. Шесть ключевых источников покрывают большинство задач диагностики.
1. pg_stat_statements — статистика запросов
Примеры запросов к pg_stat_statements
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- Топ-10 самых тяжёлых запросов по общему времени
SELECT
queryid,
substr(query, 1, 100) AS query,
calls,
round(total_exec_time::numeric, 2) AS total_time_ms,
round(mean_exec_time::numeric, 2) AS avg_time_ms,
rows
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;
-- Запросы с наибольшим количеством чтений с диска
SELECT
substr(query, 1, 80) AS query,
calls, shared_blks_hit, shared_blks_read,
round(100.0 * shared_blks_hit / NULLIF(shared_blks_hit + shared_blks_read, 0), 2) AS cache_hit_pct
FROM pg_stat_statements
ORDER BY shared_blks_read DESC
LIMIT 10;
2. pg_stat_user_tables — статистика по таблицам
Пример
SELECT
relname AS table_name,
seq_scan, -- много Seq Scan — нужен индекс?
idx_scan, -- количество Index Scan
n_tup_ins AS inserts, n_tup_upd AS updates, n_tup_del AS deletes,
n_dead_tup AS dead_tuples,
last_autovacuum
FROM pg_stat_user_tables
ORDER BY seq_scan DESC;
3. pg_stat_user_indexes — неиспользуемые индексы
Пример
SELECT
schemaname, tablename, indexrelname,
idx_scan, -- 0 = не используется
pg_size_pretty(pg_relation_size(indexrelid)) AS index_size
FROM pg_stat_user_indexes
WHERE idx_scan = 0
ORDER BY pg_relation_size(indexrelid) DESC;
4. pg_stat_activity — текущие сессии и запросы
Пример
SELECT
pid, usename, state,
now() - query_start AS duration,
wait_event_type, wait_event,
substr(query, 1, 100) AS query
FROM pg_stat_activity
WHERE state = 'active' AND pid != pg_backend_pid()
ORDER BY duration DESC;
-- Завершить зависший запрос
SELECT pg_cancel_backend(pid); -- мягкое (SIGINT)
SELECT pg_terminate_backend(pid); -- жёсткое (SIGTERM)
5. Размер таблиц и индексов
Пример
SELECT
relname AS table_name,
pg_size_pretty(pg_total_relation_size(relid)) AS total_size,
pg_size_pretty(pg_relation_size(relid)) AS table_size,
pg_size_pretty(pg_total_relation_size(relid) - pg_relation_size(relid)) AS index_size
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 10;
6. Cache hit ratio
Пример
SELECT
sum(blks_hit) * 100.0 / NULLIF(sum(blks_hit) + sum(blks_read), 0) AS cache_hit_ratio
FROM pg_stat_database;
-- Хорошее значение: > 99%
На собеседовании: назовите три ключевых представления — pg_stat_statements (какие запросы тормозят), pg_stat_user_tables (много ли Seq Scan), pg_stat_activity (что выполняется сейчас). Cache hit ratio > 99% — признак здоровой системы, < 95% — нужно увеличить shared_buffers.