
СЕРВЕРНЫЕ ПРОЦЕССЫ
~~~~~~~~~~~~~~~~~~

Включим сбор статистики ввода-вывода и выполнения функций.

        => 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         | 20986
        waiting     | f
        state       | active
        backend_xid | 
        query       | select pid, waiting, state, backend_xid, query from pg_stat_activity;
        -[ RECORD 2 ]----------------------------------------------------------------------
        pid         | 20991
        waiting     | f
        state       | idle in transaction
        backend_xid | 1091
        query       | update t set n=n+1;
        -[ RECORD 3 ]----------------------------------------------------------------------
        pid         | 20996
        waiting     | t
        state       | active
        backend_xid | 1092
        query       | update t set n=n+2;
        

-----------------------------------------------------------------------

Можно сравнить с тем, что показывает операционная система:

ps -o pid,command --ppid `head -n 1 $PGDATA/postmaster.pid`
  PID COMMAND
20921 postgres: checkpointer process  
20922 postgres: writer process     
20923 postgres: wal writer process  
20924 postgres: autovacuum launcher process  
20925 postgres: stats collector process  
20986 postgres: postgres postgres [local] idle
20991 postgres: postgres postgres [local] idle in transaction
20996 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 | 1091
        pid           | 20996
        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 | 1091
        pid           | 20991
        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         | 20986
        waiting     | f
        state       | active
        backend_xid | 
        query       | select pid, waiting, state, backend_xid, query from pg_stat_activity;
        -[ RECORD 2 ]----------------------------------------------------------------------
        pid         | 20996
        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     | 250
        checkpoints_req       | 24
        checkpoint_write_time | 41829
        checkpoint_sync_time  | 1340
        buffers_checkpoint    | 23472
        buffers_clean         | 0
        maxwritten_clean      | 0
        buffers_backend       | 13422
        buffers_backend_fsync | 0
        buffers_alloc         | 15184
        stats_reset           | 2015-12-25 09:56:29.456122+03
        

* buffers_clean      - количество страниц, записанных bgwriter
* buffers_checkpoint - количество страниц, записанных checkpointer
* buffers_backend    - количество страниц, записанных серверными процессами

-----------------------------------------------------------------------

СТАТИСТИКА ОБРАЩЕНИЙ К ОБЪЕКТАМ БД
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Можно посмотреть статистику обращения к таблицам:

        => select * from pg_stat_all_tables where relid='t'::regclass;
        -[ RECORD 1 ]-------+-------
        relid               | 16889
        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         | 16889
        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          | 12185
        datname        | postgres
        numbackends    | 2
        xact_commit    | 2992
        xact_rollback  | 34
        blks_read      | 13526
        blks_hit       | 3251266
        tup_returned   | 13005194
        tup_fetched    | 584499
        tup_inserted   | 2001871
        tup_updated    | 87
        tup_deleted    | 764
        conflicts      | 0
        temp_files     | 2
        temp_bytes     | 28000000
        deadlocks      | 0
        blk_read_time  | 0.941
        blk_write_time | 0
        stats_reset    | 2015-12-25 09:56:29.957574+03
        

-----------------------------------------------------------------------

Наконец, можно посмотреть статистику в терминах ввода-вывода.

        => select * from pg_statio_all_tables where relid='t'::regclass;
        -[ RECORD 1 ]---+-------
        relid           | 16889
        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          | 12185
        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    | 2015-12-30 15:27:27.905855+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     | 16896
        schemaname | public
        funcname   | f1
        calls      | 100
        total_time | 0.237
        self_time  | 0.237
        

        => commit;
        COMMIT

-----------------------------------------------------------------------

АНАЛИЗ ЖУРНАЛА
~~~~~~~~~~~~~~

Посмотрим самый простой случай. Например, нас интересуют сообщения FATAL:

grep FATAL ~postgres/logfile | tail -n 10
FATAL:  terminating connection due to administrator command
FATAL:  database "u1" does not exist
FATAL:  role "u1" is not permitted to log in
FATAL:  database "–" does not exist
FATAL:  database "–" does not exist
FATAL:  database "–" does not exist
FATAL:  database "–" does not exist
FATAL:  database "‑" does not exist
FATAL:  terminating connection due to administrator command
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 | 500524.84506687
        

-----------------------------------------------------------------------

И посмотрим журнал:

egrep ^!!! ~postgres/logfile | tail -n 2
!!! pid=20986: LOG:  statement: select sum(random()) from generate_series(1,1000000);
!!! pid=20986: LOG:  duration: 236.752 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
