СЕРВЕРНЫЕ ПРОЦЕССЫ ~~~~~~~~~~~~~~~~~~ Включим сбор статистики ввода-вывода и выполнения функций. => alter system set track_io_timing=on; ALTER SYSTEM => alter system set track_functions='all'; ALTER SYSTEM pg_ctl reload server signaled ----------------------------------------------------------------------- Рассмотрим несколько представлений, позволяющих посмотреть собранную статистику. Начнем с информации о текущем состоянии системы. Запустим два сеанса, один из которых изменяет таблицу, а второй пытается изменить и блокируется. => create table t(n numeric); CREATE TABLE => insert into t values(42); INSERT 0 1 | => begin; | BEGIN | => update t set n=n+1; | UPDATE 1 || => update t set n=n+2; ----------------------------------------------------------------------- Посмотрим информацию о серверных процессах. => \x Expanded display is on. => select pid, waiting, state, backend_xid, query from pg_stat_activity; -[ RECORD 1 ]---------------------------------------------------------------------- pid | 19356 waiting | f state | active backend_xid | query | select pid, waiting, state, backend_xid, query from pg_stat_activity; -[ RECORD 2 ]---------------------------------------------------------------------- pid | 19361 waiting | f state | idle in transaction backend_xid | 918 query | update t set n=n+1; -[ RECORD 3 ]---------------------------------------------------------------------- pid | 19365 waiting | t state | active backend_xid | 919 query | update t set n=n+2; ----------------------------------------------------------------------- Можно сравнить с тем, что показывает операционная система: ps -o pid,command --ppid `head -n 1 $PGDATA/postmaster.pid` PID COMMAND 19288 postgres: checkpointer process 19289 postgres: writer process 19290 postgres: wal writer process 19291 postgres: autovacuum launcher process 19292 postgres: stats collector process 19356 postgres: postgres postgres [local] idle 19361 postgres: postgres postgres [local] idle in transaction 19365 postgres: postgres postgres [local] UPDATE waiting ----------------------------------------------------------------------- Как можно использовать эту информацию, чтобы "убить" блокирующий сеанс? Посмотрим на блокировки. => select pid as blocked_pid from pg_stat_activity where waiting \gset => select locktype, transactionid, pid, mode, granted -> from pg_locks -> where pid=:blocked_pid and not granted; -[ RECORD 1 ]-+-------------- locktype | transactionid transactionid | 918 pid | 19365 mode | ShareLock granted | f ----------------------------------------------------------------------- Теперь мы можем вычислить блокирующий процесс и вызвать функцию для его завершения. Вот блокировка, которая нам мешает: => select transactionid as blocking_xid from pg_locks where pid=:blocked_pid and not granted \gset => select locktype, transactionid, pid, mode, granted -> from pg_locks -> where transactionid=:blocking_xid and granted; -[ RECORD 1 ]-+-------------- locktype | transactionid transactionid | 918 pid | 19361 mode | ExclusiveLock granted | t ----------------------------------------------------------------------- => select pid as blocking_pid from pg_locks where transactionid=:blocking_xid and granted \gset => select pg_terminate_backend(:blocking_pid); -[ RECORD 1 ]--------+-- pg_terminate_backend | t ----------------------------------------------------------------------- Проверим состояние серверных процессов. => select pid, waiting, state, backend_xid, query from pg_stat_activity; -[ RECORD 1 ]---------------------------------------------------------------------- pid | 19356 waiting | f state | active backend_xid | query | select pid, waiting, state, backend_xid, query from pg_stat_activity; -[ RECORD 2 ]---------------------------------------------------------------------- pid | 19365 waiting | f state | idle backend_xid | query | update t set n=n+2; Осталось только два, причем заблокированный успешно завершил транзакцию. ----------------------------------------------------------------------- ФОНОВЫЕ ПРОЦЕССЫ ~~~~~~~~~~~~~~~~ Можно посмотреть статистику по процессам background_writer и checkpointer: => select * from pg_stat_bgwriter; -[ RECORD 1 ]---------+------------------------------ checkpoints_timed | 0 checkpoints_req | 29 checkpoint_write_time | 12228 checkpoint_sync_time | 673 buffers_checkpoint | 19132 buffers_clean | 0 maxwritten_clean | 0 buffers_backend | 12702 buffers_backend_fsync | 0 buffers_alloc | 14322 stats_reset | 2016-06-16 17:23:04.663439+03 * buffers_clean - количество страниц, записанных bgwriter * buffers_checkpoint - количество страниц, записанных checkpointer * buffers_backend - количество страниц, записанных серверными процессами ----------------------------------------------------------------------- СТАТИСТИКА ОБРАЩЕНИЙ К ОБЪЕКТАМ БД ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Можно посмотреть статистику обращения к таблицам: => select * from pg_stat_all_tables where relid='t'::regclass; -[ RECORD 1 ]-------+------- relid | 24879 schemaname | public relname | t seq_scan | 2 seq_tup_read | 2 idx_scan | idx_tup_fetch | n_tup_ins | 1 n_tup_upd | 2 n_tup_del | 0 n_tup_hot_upd | 2 n_live_tup | 1 n_dead_tup | 2 n_mod_since_analyze | 2 last_vacuum | last_autovacuum | last_analyze | last_autoanalyze | vacuum_count | 0 autovacuum_count | 0 analyze_count | 0 autoanalyze_count | 0 ----------------------------------------------------------------------- Существуют вариации: * pg_stat_user_tables - только таблицы пользователя * pg_stat_sys_tables - только системные таблицы И аналогичные варианты для индексов: * pg_stat_all_indexes - все индексы * pg_stat_user_indexes - только индексы пользователя * pg_stat_sys_indexes - только системные индексы ----------------------------------------------------------------------- Также можно посмотреть статистику текущей транзакции: => begin; BEGIN => insert into t values (1), (2), (3); INSERT 0 3 => update t set n=10 where n=1; UPDATE 1 => delete from t where n < 4; DELETE 2 => select * from pg_stat_xact_all_tables where relid='t'::regclass; -[ RECORD 1 ]-+------- relid | 24879 schemaname | public relname | t seq_scan | 2 seq_tup_read | 8 idx_scan | idx_tup_fetch | n_tup_ins | 3 n_tup_upd | 1 n_tup_del | 2 n_tup_hot_upd | 1 => commit; COMMIT ----------------------------------------------------------------------- Можно посмотреть статистику по всей базе данных: => select * from pg_stat_database where datname='postgres'; -[ RECORD 1 ]--+------------------------------ datid | 12175 datname | postgres numbackends | 2 xact_commit | 303 xact_rollback | 30 blks_read | 12943 blks_hit | 2115059 tup_returned | 11023884 tup_fetched | 12640 tup_inserted | 2001539 tup_updated | 54 tup_deleted | 152 conflicts | 0 temp_files | 2 temp_bytes | 28000000 deadlocks | 0 blk_read_time | 1.175 blk_write_time | 0 stats_reset | 2016-06-16 17:23:05.212494+03 ----------------------------------------------------------------------- Наконец, можно посмотреть статистику в терминах ввода-вывода. => select * from pg_statio_all_tables where relid='t'::regclass; -[ RECORD 1 ]---+------- relid | 24879 schemaname | public relname | t heap_blks_read | 1 heap_blks_hit | 4 idx_blks_read | idx_blks_hit | toast_blks_read | 0 toast_blks_hit | 0 tidx_blks_read | 0 tidx_blks_hit | 0 ----------------------------------------------------------------------- Существуют вариации: * pg_statio_user_tables - только таблицы пользователя * pg_statio_sys_tables - только системные таблицы Аналогичные варианты для индексов: * pg_statio_all_indexes - все индексы * pg_statio_user_indexes - только индексы пользователя * pg_statio_sys_indexes - только системные индексы А также для последовательностей: * pg_statio_all_sequences - все последовательности * pg_statio_user_sequences - только последовательности пользователя * pg_statio_sys_sequences - только системные последовательности (которых нет) ----------------------------------------------------------------------- При желании статистику можно сбросить: => select pg_stat_reset(); -[ RECORD 1 ]-+- pg_stat_reset | Чтобы увидеть изменения, надо дождаться, пока коллектор запишет новый снимок... sleep 5 => select * from pg_stat_database where datname='postgres'; -[ RECORD 1 ]--+------------------------------ datid | 12175 datname | postgres numbackends | 2 xact_commit | 0 xact_rollback | 0 blks_read | 0 blks_hit | 0 tup_returned | 0 tup_fetched | 0 tup_inserted | 0 tup_updated | 0 tup_deleted | 0 conflicts | 0 temp_files | 0 temp_bytes | 0 deadlocks | 0 blk_read_time | 0 blk_write_time | 0 stats_reset | 2016-06-16 17:23:37.731546+03 Можно сбросить статистику и по отдельным объектам (\df pg_stat_reset*). ----------------------------------------------------------------------- СТАТИСТИКА ВЫЗОВА ФУНКЦИЙ ~~~~~~~~~~~~~~~~~~~~~~~~~ Создадим функцию: => create function f() returns integer as $$ select 1; $$ language sql; CREATE FUNCTION => begin; BEGIN => select sum(f()) from generate_series(1,100); -[ RECORD 1 ] sum | 100 => select * from pg_stat_xact_user_functions; (No rows) => commit; COMMIT Почему нет статистики? ----------------------------------------------------------------------- Дело в том, что простые функции подставляются непосредственно в запрос. Собственно функция в данном случае не вызывается. ----------------------------------------------------------------------- Создадим более сложную функцию. => create function f1() returns integer as $$ begin return 1; end; $$ language plpgsql; CREATE FUNCTION => begin; BEGIN => select sum(f1()) from generate_series(1,100); -[ RECORD 1 ] sum | 100 => select * from pg_stat_xact_user_functions; -[ RECORD 1 ]------ funcid | 24886 schemaname | public funcname | f1 calls | 100 total_time | 0.153 self_time | 0.153 => commit; COMMIT ----------------------------------------------------------------------- АНАЛИЗ ЖУРНАЛА ~~~~~~~~~~~~~~ Посмотрим самый простой случай. Например, нас интересуют сообщения FATAL: grep FATAL ~postgres/logfile | tail -n 10 grep FATAL /home/postgres/logfile FATAL: the database system is starting up FATAL: terminating connection due to administrator command Сообщение terminating connection вызвано тем, что мы завершали блокирующий процесс. ----------------------------------------------------------------------- Немного изменим формат выдачи журнала. => alter system set log_line_prefix='!!! pid=%p: '; ALTER SYSTEM => alter system set log_duration='on'; ALTER SYSTEM => alter system set log_statement='all'; ALTER SYSTEM pg_ctl reload server signaled ----------------------------------------------------------------------- Теперь выполним какую-нибудь команду: => select sum(random()) from generate_series(1,1000000); -[ RECORD 1 ]--------- sum | 500188.629603776 ----------------------------------------------------------------------- И посмотрим журнал: egrep ^!!! ~postgres/logfile | tail -n 2 !!! pid=19356: LOG: statement: select sum(random()) from generate_series(1,1000000); !!! pid=19356: LOG: duration: 358.463 ms ----------------------------------------------------------------------- Конец демонстрации. ----------------------------------------------------------------------- => alter system set track_io_timing=default; ALTER SYSTEM => alter system set track_functions=default; ALTER SYSTEM => alter system set log_line_prefix=default; ALTER SYSTEM => alter system set log_duration=default; ALTER SYSTEM => alter system set log_statement=default; ALTER SYSTEM pg_ctl reload server signaled => \q | => \q || => \q