F.56. pgpro_usage — статистика отношений и функций в разрезе пользователей #

Расширение pgpro_usage предоставляет статистику доступа к отношениям и вызовов функций в разрезе пользователей.

Примечание

Если сервер выключен, собранная pgpro_usage статистика хранится в файле $PGDATA/pg_stat/pgpro_usage.stat. Чтобы сохранить статистику при переключении на резервный сервер, вам нужно вручную скопировать файл с предыдущего основного сервера или восстановить его из резервной копии.

F.56.1. Установка расширения pgpro_usage #

Расширение pgpro_usage включено в состав Postgres Pro Enterprise как стандартное расширение. Чтобы задействовать pgpro_usage, выполните следующие действия:

  1. Добавьте pgpro_usage в переменную shared_preload_libraries в файле postgresql.conf:

    shared_preload_libraries = 'pgpro_usage'
  2. Перезапустите сервер базы данных, чтобы изменения вступили в силу. Чтобы убедиться, что библиотека pgpro_usage установлена корректно, вы можете выполнить следующую команду:

    SHOW shared_preload_libraries;
  3. Создайте расширение pgpro_usage, выполнив следующий запрос:

    CREATE EXTENSION pgpro_usage;

F.56.2. Удаление расширения pgpro_usage #

Чтобы корректно удалить расширение pgpro_usage, выполните следующие действия:

  1. Удалите расширение pgpro_usage, выполнив следующий запрос:

    DROP EXTENSION pgpro_usage;
  2. Удалите pgpro_usage из переменной shared_preload_libraries в файле postgresql.conf.

F.56.3. Функции #

Чтобы собирать статистику доступа отношений и вызовов функций в разрезе пользователей, pgpro_usage предоставляет SQL-интерфейс, состоящий из нескольких функций и представлений.

F.56.3.1. Функции для сбора статистики отношений в разрезе пользователей #

pg_stat_get_read_req_per_user(targetoid oid, roleoid oid) → BIGINT

Возвращает число запросов пользователя/роли, указанной в roleoid, на чтение таблицы/индекса, указанного в targetoid.

pg_stat_get_insert_req_per_user(targetoid oid, roleoid oid) → BIGINT

Возвращает число запросов пользователя/роли, указанной в roleoid, на вставку данных в таблицу, указанную в targetoid.

pg_stat_get_update_req_per_user(targetoid oid, roleoid oid) → BIGINT

Возвращает число запросов пользователя/роли, указанной в roleoid, на обновление данных в таблице, указанной в targetoid.

pg_stat_get_delete_req_per_user(targetoid oid, roleoid oid) → BIGINT

Возвращает число запросов пользователя/роли, указанной в roleoid, на удаление данных из таблицы, указанной в targetoid.

pg_stat_get_truncate_req_per_user(targetoid oid, roleoid oid) → BIGINT

Возвращает число запросов пользователя/роли, указанной в roleoid, на опустошение таблицы, указанной в targetoid.

pg_stat_get_grants_given_per_user(targetoid oid, roleoid oid) → BIGINT

Возвращает число команд GRANT и REVOKE, выполненных пользователем/ролью, указанной в roleoid, для таблицы, указанной в targetoid.

pg_stat_get_last_read_per_user(targetoid oid, roleoid oid) → timestamp with timezone

Возвращает дату и время, когда пользователь/роль, указанная в roleoid, в последний раз выполнила SELECT для таблицы, указанной в targetoid.

pg_stat_get_last_insert_per_user(targetoid oid, roleoid oid) → timestamp with timezone

Возвращает дату и время, когда пользователь/роль, указанная в roleoid, в последний раз выполнила INSERT для таблицы, указанной в targetoid.

pg_stat_get_last_update_per_user(targetoid oid, roleoid oid) → timestamp with timezone

Возвращает дату и время, когда пользователь/роль, указанная в roleoid, в последний раз выполнила UPDATE для таблицы, указанной в targetoid.

pg_stat_get_last_delete_per_user(targetoid oid, roleoid oid) → timestamp with timezone

Возвращает дату и время, когда пользователь/роль, указанная в roleoid, в последний раз выполнила DELETE для таблицы, указанной в targetoid.

pg_stat_get_last_truncate_per_user(targetoid oid, roleoid oid) → timestamp with timezone

Возвращает дату и время, когда пользователь/роль, указанная в roleoid, в последний раз выполнила TRUNCATE для таблицы, указанной в targetoid.

F.56.3.2. Функции для сбора статистики функций в разрезе пользователей #

pg_stat_get_func_calls_per_user(targetoid oid, roleoid oid) → BIGINT

Возвращает число вызовов функции, указанной в targetoid, пользователем/ролью, указанной в roleoid.

pg_stat_get_func_grants_given_per_user(targetoid oid, roleoid oid) → BIGINT

Возвращает число команд GRANT и REVOKE, выполненных пользователем/ролью, указанной в roleoid, для функции, указанной в targetoid.

F.56.3.3. Сервисные функции #

pgpro_usage_reset(full_reset bool default false) → void

Сбрасывает статистику pgpro_usage. Если для параметра full_reset задано значение true, сбрасывается вся статистика. Если для параметра full_reset задано значение false, сброс не затрагивает статистику последнего использования таблиц.

pgpro_usage_get_last_reset_time() → timestamp with time zone

Время последнего сброса статистики pgpro_usage.

F.56.4. Представления #

F.56.4.1. Представление pg_stat_all_tables_per_user #

Представление pg_stat_all_tables_per_user содержит по одной строке для каждой комбинации пользователя/роли и таблицы в текущей базе данных (включая TOAST-таблицы) и показывает статистику разных типов запросов пользователей к таблицам.

Таблица F.43. Столбцы pg_stat_all_tables_per_user

Столбец Тип

Описание

userid oid

OID пользователя/роли

username name

Имя пользователя/роли

relid oid

OID таблицы

nspname name

Имя схемы, в которой находится эта таблица

relname name

Имя этой таблицы

n_reads bigint

Число запросов этого пользователя/роли на чтение этой таблицы

n_inserts INT

Число запросов этого пользователя/роли на вставку данных в эту таблицу

n_updates INT

Число запросов от пользователя/роли на обновление данных в этой таблице

n_deletes INT

Число запросов этого пользователя/роли на удаление данных из этой таблицы

n_truncates INT

Число запросов пользователя/роли на опустошение этой таблицы

n_grants_given INT

Число команд GRANT и REVOKE, выполненных этим пользователем/ролью для этой таблицы


F.56.4.2. Представление pg_stat_all_tables_last_usage #

Представление pg_stat_all_tables_last_usage содержит одну строку для каждой комбинации пользователя/роли и таблицы в текущей базе данных (включая TOAST-таблицы) и показывает дату и время последнего выполнения пользователями операций с таблицами.

Таблица F.44. Столбцы pg_stat_all_tables_last_usage

Столбец Тип

Описание

userid oid

OID пользователя/роли

username name

Имя пользователя/роли

nspname name

Имя пространства имён

relid oid

OID таблицы

relname name

Имя этой таблицы

last_read timestamp with timezone

Дата и время последнего чтения этой таблицы этим пользователем/ролью

last_insert timestamp with timezone

Дата и время последней вставки данных в эту таблицу этим пользователем/ролью

last_update timestamp with timezone

Дата и время последнего обновления этой таблицы этим пользователем/ролью

last_delete timestamp with timezone

Дата и время последнего удаления данных из этой таблицы этим пользователем/ролью

last_truncate timestamp with timezone

Дата и время последнего опустошения этой таблицы этим пользователем/ролью


F.56.4.3. Представление pg_stat_all_functions_per_user #

Представление pg_stat_all_functions_per_user содержит по одной строке для каждой комбинации пользователя/роли и пользовательской функции/хранимой процедуры/системной функции в текущей базе данных и показывает статистику вызовов функций и выдачи прав пользователями.

Таблица F.45. Столбцы pg_stat_all_functions_per_user

Столбец Тип

Описание

userid oid

OID пользователя/роли

username name

Имя пользователя/роли

funcid oid

OID функции

nspname name

Имя схемы, в которой находится функция

funcname name

Имя этой функции

calls INT

Число вызовов этой функции этим пользователем/ролью

grants_given INT

Число команд GRANT и REVOKE, выполненных этим пользователем/ролью для этой функции


F.56.4.4. Представление pgpro_usage_stats_privileges_usage #

Представление pgpro_usage_stats_privileges_usage содержит по одной строке для каждой комбинации роли, права и объекта (таблицы или функции), на который роли имеют права. Строки показывают, каким образом были выданы права и были ли они использованы.

Таблица F.46. Столбцы pgpro_usage_stats_privileges_usage

Столбец Тип

Описание

usename name

Имя пользователя

access text

Тип права: SELECT, INSERT, UPDATE, DELETE или TRUNCATE для таблицы и EXECUTE для функции

nspname name

Имя схемы, в которой находится объект (таблица или функция)

targetname name

Имя этого объекта (таблицы или функции)

provider name

Имя роли, членство в которой позволило этой роли получить это право

grantee name

Имя роли, членство в которой позволило этой роли получить это право, или "public", если это право было выдано всем ролям с помощью GRANT ... TO PUBLIC.

kind text

Тип объекта: FUNCTION или RELATION

used boolean

Было ли использовано это право


F.56.5. Параметры конфигурации #

pgpro_usage.max (integer)

Определяет максимальное число пар объект-пользователь, которое хранит статистика. Объектом может быть таблица, функция или процедура. Вы можете уменьшить это значение для экономии памяти или увеличить его при использовании больших баз данных. Если расширению pgpro_usage требуется превысить заданное значение при записи статистики, новая запись не создаётся и отображается предупреждение «WARNING: max number of pgpro_usage records exceeded» (ПРЕДУПРЕЖДЕНИЕ: превышено максимальное число записей pgpro_usage).

Значение по умолчанию — 10000.

F.56.6. Пример #

Этот пример демонстрирует использование расширения pgpro_usage.

Сначала создадим расширение:

postgres=# create extension pgpro_usage;
CREATE EXTENSION

Теперь просмотрим статистику использования. Для этого создадим пользователя, таблицу и процедуру, после чего выдадим пользователю доступ к таблице:

postgres=# CREATE USER u1;
CREATE ROLE
postgres=# CREATE TABLE t1(val int);
CREATE TABLE
postgres=# GRANT all on t1 to u1;
GRANT
postgres=# CREATE PROCEDURE p1() AS $$ BEGIN RAISE NOTICE 'Here we are'; END; $$ LANGUAGE plpgsql;
CREATE PROCEDURE

Выведем статистику использования всех таблиц:

postgres=# SELECT * FROM pg_stat_all_tables_per_user;
 userid | username | relid | nspname | relname | n_reads | n_inserts | n_updates | n_deletes | n_truncates | n_grants_given
--------+----------+-------+---------+---------+---------+-----------+-----------+-----------+-------------+----------------
     10 | postgres | 16445 | public  | t1      |       0 |         0 |         0 |         0 |           0 |              1
(1 row)

Сделаем то же самое для всех функций:

postgres=# SELECT * FROM pg_stat_all_functions_per_user;
 userid | username | funcid | nspname |                funcname                | calls | grants_given
--------+----------+--------+---------+----------------------------------------+-------+--------------
     10 | postgres | 16385  | public  | pgpro_usage_reset                      |     0 |            1
     10 | postgres | 16386  | public  | pgpro_usage                            |     0 |            1
     10 | postgres | 16387  | public  | pgpro_usage_full                       |     0 |            1
     10 | postgres | 16397  | public  | pg_stat_get_func_calls_per_user        |     2 |            0
     10 | postgres | 16398  | public  | pg_stat_get_func_grants_given_per_user |     1 |            0
     10 | postgres | 16399  | public  | pg_stat_get_read_req_per_user          |     1 |            0
     10 | postgres | 16400  | public  | pg_stat_get_insert_req_per_user        |     1 |            0
     10 | postgres | 16401  | public  | pg_stat_get_update_req_per_user        |     1 |            0
     10 | postgres | 16402  | public  | pg_stat_get_delete_req_per_user        |     1 |            0
     10 | postgres | 16403  | public  | pg_stat_get_truncate_req_per_user      |     1 |            0
     10 | postgres | 16404  | public  | pg_stat_get_grants_given_per_user      |     1 |            0
(11 rows)

Приведённый выше вывод содержит только действия суперпользователя, который выдал доступ к таблице и несколько раз вызвал функции расширения при отправке запросов к приведённым выше представлениям. Столбец grants_given ненулевой в трёх строках. Они соответствуют отзыву прав у public при создании расширения. Созданный пользователь не включён в статистику, так как он не выполнял никаких действий.

Восполним этот пробел и подключимся к базе данных как пользователь u1.

postgres=# \c - u1
You are now connected to database "postgres" as user "u1".
postgres=> insert into t1(val) values (1);
INSERT 0 1
postgres=> insert into t1(val) values (2);
INSERT 0 1
postgres=> select * from t1;
 val
-----
   1
   2
(2 rows)
postgres=> call p1();
NOTICE:  Here we are
CALL

Мы выполнили две вставки в таблицу, отправили к ней один запрос и один раз вызвали процедуру. Переключимся обратно на суперпользователя и снова просмотрим статистику:

postgres=> \c - postgres
You are now connected to database "postgres" as user "postgres".
postgres=# SELECT * FROM pg_stat_all_tables_per_user;
 userid | username | relid | nspname | relname | n_reads | n_inserts | n_updates | n_deletes | n_truncates | n_grants_given
--------+----------+-------+---------+---------+---------+-----------+-----------+-----------+-------------+----------------
  16444 | u1       | 16445 | public  | t1      |       1 |         2 |         0 |         0 |           0 |              0
     10 | postgres | 16445 | public  | t1      |       0 |         0 |         0 |         0 |           0 |              1
(2 rows)
postgres=# SELECT * FROM pg_stat_all_functions_per_user;
 userid | username | funcid | nspname |                funcname                | calls | grants_given
--------+----------+--------+---------+----------------------------------------+-------+--------------
     10 | postgres | 16385  | public  | pgpro_usage_reset                      |     0 |            1
     10 | postgres | 16386  | public  | pgpro_usage                            |     0 |            1
     10 | postgres | 16387  | public  | pgpro_usage_full                       |     0 |            1
     10 | postgres | 16397  | public  | pg_stat_get_func_calls_per_user        |     4 |            0
     10 | postgres | 16398  | public  | pg_stat_get_func_grants_given_per_user |     2 |            0
     10 | postgres | 16399  | public  | pg_stat_get_read_req_per_user          |     2 |            0
     10 | postgres | 16400  | public  | pg_stat_get_insert_req_per_user        |     2 |            0
     10 | postgres | 16401  | public  | pg_stat_get_update_req_per_user        |     2 |            0
     10 | postgres | 16402  | public  | pg_stat_get_delete_req_per_user        |     2 |            0
     10 | postgres | 16403  | public  | pg_stat_get_truncate_req_per_user      |     2 |            0
     10 | postgres | 16404  | public  | pg_stat_get_grants_given_per_user      |     2 |            0
  16444 | u1       | 16448  | public  | p1                                     |     1 |            0
(12 rows)

Обе таблицы теперь содержат строки, соответствующие операциям пользователя u1: две вставки и одно чтение таблицы, а также одно выполнение процедуры.

Теперь просмотрим статистику последнего использования. Мы сможем увидеть временные метки, показывающие, когда пользователь выполнил вставку и чтение.

postgres=# select * from pg_stat_all_tables_last_usage;
 userid | username | nspname | relid | relname |           last_read           |         last_insert          | last_update | last_delete | last_truncate
--------+----------+---------+-------+---------+-------------------------------+------------------------------+-------------+-------------+---------------
  16444 | u1       | public  | 16445 | t1      | 2024-11-30 01:06:24.578642+03 | 2024-11-30 01:06:17.03442+03 |             |             |
(1 row)

Дополним статистику чтением от суперпользователя:

postgres=# select * from t1;
 val
-----
   1
   2
(2 rows)
postgres=# select * from pg_stat_all_tables_last_usage;
 userid | username | nspname | relid | relname |           last_read           |         last_insert          | last_update | last_delete | last_truncate
--------+----------+---------+-------+---------+-------------------------------+------------------------------+-------------+-------------+---------------
     10 | postgres | public  | 16445 | t1      | 2024-11-30 01:09:29.994188+03 |                              |             |             |
  16444 | u1       | public  | 16445 | t1      | 2024-11-30 01:06:24.578642+03 | 2024-11-30 01:06:17.03442+03 |             |             |
(2 rows)

Убедимся, что временная метка last_read обновилась:

postgres=# select * from t1;
 val
-----
   1
   2
(2 rows)
postgres=# select * from pg_stat_all_tables_last_usage;
 userid | username | nspname | relid | relname |           last_read           |         last_insert          | last_update | last_delete | last_truncate
--------+----------+---------+-------+---------+-------------------------------+------------------------------+-------------+-------------+---------------
     10 | postgres | public  | 16445 | t1      | 2024-11-30 01:10:28.122489+03 |                              |             |             |
  16444 | u1       | public  | 16445 | t1      | 2024-11-30 01:06:24.578642+03 | 2024-11-30 01:06:17.03442+03 |             |             |
(2 rows)

Просмотрим статистику неиспользуемых прав. Объектов, пользователей и прав может существовать много, поэтому поместим всё, что относится к этому примеру, в отдельную схему. Так будет проще фильтровать результаты. Создаём схему и таблицу внутри неё, выдаём доступ к таблице определённой групповой роли и выдаём членство в этой групповой роли отдельному пользователю:

postgres=# create schema shops;
CREATE SCHEMA
postgres=# create table shops.buildings();
CREATE TABLE
postgres=# create role manager;
CREATE ROLE
postgres=# grant all on schema shops to manager;
GRANT
postgres=# grant all on shops.buildings to manager;
GRANT
postgres=# create user vasya;
CREATE ROLE
postgres=# grant manager to vasya;
GRANT ROLE

Подключимся к базе данных от имени этого пользователя и выполним запрос к таблице:

postgres=# \c - vasya
You are now connected to database "postgres" as user "vasya".
postgres=> select * from shops.buildings;
--
(0 rows)

Теперь переключимся на суперпользователя и просмотрим статистику прав:

postgres=> \c - postgres
You are now connected to database "postgres" as user "postgres".
postgres=# select * from pgpro_usage_stats_privileges_usage where usename='vasya' and nspname='shops';
 usename |  access  | nspname | targetname | provider | grantee |   kind   | used
---------+----------+---------+------------+----------+---------+----------+------
 vasya   | INSERT   | shops   | buildings  | manager  | manager | RELATION | f
 vasya   | SELECT   | shops   | buildings  | manager  | manager | RELATION | t
 vasya   | UPDATE   | shops   | buildings  | manager  | manager | RELATION | f
 vasya   | DELETE   | shops   | buildings  | manager  | manager | RELATION | f
 vasya   | TRUNCATE | shops   | buildings  | manager  | manager | RELATION | f
(5 rows)

Статистика показывает, что пользователь vasya имеет полный доступ к таблице shops.buildings и все эти права он получил не напрямую, а как член групповой роли manager. Также видно, что из всех прав пользователь vasya использовал только SELECT. Обратите внимание, что статистика прав не показывает права суперпользователя, так как суперпользователь имеет полный доступ.

F.56. pgpro_usage — per-user statistics on relations and functions #

The pgpro_usage extension provides per-user statistics on accessing relations and calling functions.

Note

If the server is shut down, the statistics collected by pgpro_usage are stored in the $PGDATA/pg_stat/pgpro_usage.stat file. To retain these statistics when switching to a standby, you need to manually copy this file from the former primary or restore it from a backup.

F.56.1. Installing the pgpro_usage Extension #

The pgpro_usage extension is a built-in extension included into Postgres Pro Enterprise. To enable pgpro_usage, complete the following steps:

  1. Add pgpro_usage to the shared_preload_libraries variable in the postgresql.conf file:

    shared_preload_libraries = 'pgpro_usage'
    
  2. Restart the database server for the changes to take effect. To verify that the pgpro_usage library was installed correctly, you can run the following command:

    SHOW shared_preload_libraries;
    
  3. Create the pgpro_usage extension using the following query:

    CREATE EXTENSION pgpro_usage;
    

F.56.2. Uninstalling the pgpro_usage Extension #

To properly uninstall pgpro_usage, complete the following steps:

  1. Delete the pgpro_usage extension using the following query:

    DROP EXTENSION pgpro_usage;
    

  2. Remove pgpro_usage from the shared_preload_libraries variable in the postgresql.conf file.

F.56.3. Functions #

To collect per-user statistics on accessing relations and calling functions, pgpro_usage provides an SQL interface that consists of several functions and views.

F.56.3.1. Functions to Collect Per-user Statistics on Relations #

pg_stat_get_read_req_per_user(targetoid oid, roleoid oid) → BIGINT

Returns the number of requests from a user/role specified by roleoid to read a table or index specified by targetoid.

pg_stat_get_insert_req_per_user(targetoid oid, roleoid oid) → BIGINT

Returns the number of requests from a user/role specified by roleoid to insert data in a table specified by targetoid.

pg_stat_get_update_req_per_user(targetoid oid, roleoid oid) → BIGINT

Returns the number of requests from a user/role specified by roleoid to update data in a table specified by targetoid.

pg_stat_get_delete_req_per_user(targetoid oid, roleoid oid) → BIGINT

Returns the number of requests from a user/role specified by roleoid to delete data from a table specified by targetoid.

pg_stat_get_truncate_req_per_user(targetoid oid, roleoid oid) → BIGINT

Returns the number of requests from a user/role specified by roleoid to truncate a table specified by targetoid.

pg_stat_get_grants_given_per_user(targetoid oid, roleoid oid) → BIGINT

Returns the number of GRANT and REVOKE commands executed by a user/role specified by roleoid for the table specified by the targetoid.

pg_stat_get_last_read_per_user(targetoid oid, roleoid oid) → timestamp with timezone

Returns the date and time when a user/role specified by roleoid last executed SELECT from a table specified by targetoid.

pg_stat_get_last_insert_per_user(targetoid oid, roleoid oid) → timestamp with timezone

Returns the date and time when a user/role specified by roleoid last executed INSERT into a table specified by targetoid.

pg_stat_get_last_update_per_user(targetoid oid, roleoid oid) → timestamp with timezone

Returns the date and time when a user/role specified by roleoid last executed UPDATE of a table specified by targetoid.

pg_stat_get_last_delete_per_user(targetoid oid, roleoid oid) → timestamp with timezone

Returns the date and time when a user/role specified by roleoid last executed DELETE from a table specified by targetoid.

pg_stat_get_last_truncate_per_user(targetoid oid, roleoid oid) → timestamp with timezone

Returns the date and time when a user/role specified by roleoid last executed TRUNCATE of a table specified by targetoid.

F.56.3.2. Functions to Collect Per-user Statistics on Functions #

pg_stat_get_func_calls_per_user(targetoid oid, roleoid oid) → BIGINT

Returns the number of times the function specified by targetoid has been called by the user/role specified by roleoid.

pg_stat_get_func_grants_given_per_user(targetoid oid, roleoid oid) → BIGINT

Returns the number of GRANT and REVOKE commands executed by a user/role specified by roleoid for the function specified by the targetoid.

F.56.3.3. Support Functions #

pgpro_usage_reset(full_reset bool default false) → void

Resets the pgpro_usage statistics. If full_reset is true, all the statistics gets reset. If full_reset is false, last-use statistics on tables remain intact.

pgpro_usage_get_last_reset_time() → timestamp with time zone

Time at which pgpro_usage statistics were last reset.

F.56.4. Views #

F.56.4.1. pg_stat_all_tables_per_user View #

The pg_stat_all_tables_per_user view will contain one row for each user/role and each table in the current database (including TOAST tables), showing statistics about different kinds of requests for that specific table from that user.

Table F.43. pg_stat_all_tables_per_user Columns

Column Type

Description

userid oid

OID of a user/role

username name

Name of the user/role

relid oid

OID of a table

nspname name

Name of the schema that this table is in

relname name

Name of this table

n_reads bigint

Number of requests from this user/role to read this table

n_inserts INT

Number of requests from this user/role to insert data in this table

n_updates INT

Number of requests from this user/role to update data in this table

n_deletes INT

Number of requests from this user/role to delete data from this table

n_truncates INT

Number of requests from this user/role to truncate this table

n_grants_given INT

Number of GRANT and REVOKE commands executed by this user/role for this table


F.56.4.2. pg_stat_all_tables_last_usage View #

The pg_stat_all_tables_last_usage view will contain one row for each user/role and each table in the current database (including TOAST tables), showing the last date and time when that user executed different operations on that specific table.

Table F.44. pg_stat_all_tables_last_usage Columns

Column Type

Description

userid oid

OID of a user/role

username name

Name of the user/role

nspname name

Name of the namespace

relid oid

OID of a table

relname name

Name of this table

last_read timestamp with timezone

Date and time when this user/role last read this table

last_insert timestamp with timezone

Date and time when this user/role last inserted data into this table

last_update timestamp with timezone

Date and time when this user/role last updated this table

last_delete timestamp with timezone

Date and time when this user/role last deleted data from this table

last_truncate timestamp with timezone

Date and time when this user/role last truncated this table


F.56.4.3. pg_stat_all_functions_per_user View #

The pg_stat_all_functions_per_user view will contain one row for each user/role and each user function, stored procedure, or system function in the current database, showing statistics about function calls and grants given by that user.

Table F.45. pg_stat_all_functions_per_user Columns

Column Type

Description

userid oid

OID of a user/role

username name

Name of the user/role

funcid oid

OID of a function

nspname name

Name of the schema the function is in

funcname name

Name of this function

calls INT

Number of times this function has been called by this user/role

grants_given INT

Number of GRANT and REVOKE commands executed by this user/role for this function


F.56.4.4. pgpro_usage_stats_privileges_usage View #

The pgpro_usage_stats_privileges_usage view will contain one row for each role, each privilege, and each object (table or function) for which this role has this privilege. This row will show how this privilege has been given and whether it is used.

Table F.46. pgpro_usage_stats_privileges_usage Columns

Column Type

Description

usename name

Name of a user

access text

Type of a privilege: SELECT, INSERT, UPDATE, DELETE, or TRUNCATE for a table and EXECUTE for a function

nspname name

Name of the schema an object (table or function) is in

targetname name

Name of this object (table or function)

provider name

Name of the role through membership in which this role got this privilege

grantee name

Name of the role through membership in which this role got this privilege or "public" if this privilege was granted to all roles through GRANT ... TO PUBLIC.

kind text

Type of the object: FUNCTION or RELATION

used boolean

Whether this privilege was used


F.56.5. Configuration Parameters #

pgpro_usage.max (integer)

Defines the maximum number of pairs (object, user) for the statistics to store, where the object is a table or a function/procedure. Can be reduced to save the memory or increased for huge databases. If pgpro_usage needs to exceed this value when writing statistics, the new record is not created, and the WARNING: max number of pgpro_usage records exceeded warning is displayed.

The default value is 10000.

F.56.6. Example #

This example illustrates usage of the pgpro_usage extension.

First we create the extension:

postgres=# create extension pgpro_usage;
CREATE EXTENSION

Now let's try out the usage statistics. To do this, we create a user, table, and procedure and give the user access to the table:

postgres=# CREATE USER u1;
CREATE ROLE
postgres=# CREATE TABLE t1(val int);
CREATE TABLE
postgres=# GRANT all on t1 to u1;
GRANT
postgres=# CREATE PROCEDURE p1() AS $$ BEGIN RAISE NOTICE 'Here we are'; END; $$ LANGUAGE plpgsql;
CREATE PROCEDURE

Let's output all the usage statistics for all tables:

postgres=# SELECT * FROM pg_stat_all_tables_per_user;
 userid | username | relid | nspname | relname | n_reads | n_inserts | n_updates | n_deletes | n_truncates | n_grants_given
--------+----------+-------+---------+---------+---------+-----------+-----------+-----------+-------------+----------------
     10 | postgres | 16445 | public  | t1      |       0 |         0 |         0 |         0 |           0 |              1
(1 row)

Do so for all functions:

postgres=# SELECT * FROM pg_stat_all_functions_per_user;
 userid | username | funcid | nspname |                funcname                | calls | grants_given
--------+----------+--------+---------+----------------------------------------+-------+--------------
     10 | postgres | 16385  | public  | pgpro_usage_reset                      |     0 |            1
     10 | postgres | 16386  | public  | pgpro_usage                            |     0 |            1
     10 | postgres | 16387  | public  | pgpro_usage_full                       |     0 |            1
     10 | postgres | 16397  | public  | pg_stat_get_func_calls_per_user        |     2 |            0
     10 | postgres | 16398  | public  | pg_stat_get_func_grants_given_per_user |     1 |            0
     10 | postgres | 16399  | public  | pg_stat_get_read_req_per_user          |     1 |            0
     10 | postgres | 16400  | public  | pg_stat_get_insert_req_per_user        |     1 |            0
     10 | postgres | 16401  | public  | pg_stat_get_update_req_per_user        |     1 |            0
     10 | postgres | 16402  | public  | pg_stat_get_delete_req_per_user        |     1 |            0
     10 | postgres | 16403  | public  | pg_stat_get_truncate_req_per_user      |     1 |            0
     10 | postgres | 16404  | public  | pg_stat_get_grants_given_per_user      |     1 |            0
(11 rows)

In the above output, you can only see superuser operations, who once granted access on a table and several times called the extension functions when querying the above views. The grants_given column is non-zero in three rows. They correspond to revoking permissions from public during creation of the extension. The newly created user is not included in the statistics since he did nothing.

Let's fill this gap and connect to the database as the u1 user.

postgres=# \c - u1
You are now connected to database "postgres" as user "u1".
postgres=> insert into t1(val) values (1);
INSERT 0 1
postgres=> insert into t1(val) values (2);
INSERT 0 1
postgres=> select * from t1;
 val
-----
   1
   2
(2 rows)
postgres=> call p1();
NOTICE:  Here we are
CALL

We did two inserts in the table, queried it once, and once called the procedure. Let's switch back to the superuser and look at the statistics again:

postgres=> \c - postgres
You are now connected to database "postgres" as user "postgres".
postgres=# SELECT * FROM pg_stat_all_tables_per_user;
 userid | username | relid | nspname | relname | n_reads | n_inserts | n_updates | n_deletes | n_truncates | n_grants_given
--------+----------+-------+---------+---------+---------+-----------+-----------+-----------+-------------+----------------
  16444 | u1       | 16445 | public  | t1      |       1 |         2 |         0 |         0 |           0 |              0
     10 | postgres | 16445 | public  | t1      |       0 |         0 |         0 |         0 |           0 |              1
(2 rows)
postgres=# SELECT * FROM pg_stat_all_functions_per_user;
 userid | username | funcid | nspname |                funcname                | calls | grants_given
--------+----------+--------+---------+----------------------------------------+-------+--------------
     10 | postgres | 16385  | public  | pgpro_usage_reset                      |     0 |            1
     10 | postgres | 16386  | public  | pgpro_usage                            |     0 |            1
     10 | postgres | 16387  | public  | pgpro_usage_full                       |     0 |            1
     10 | postgres | 16397  | public  | pg_stat_get_func_calls_per_user        |     4 |            0
     10 | postgres | 16398  | public  | pg_stat_get_func_grants_given_per_user |     2 |            0
     10 | postgres | 16399  | public  | pg_stat_get_read_req_per_user          |     2 |            0
     10 | postgres | 16400  | public  | pg_stat_get_insert_req_per_user        |     2 |            0
     10 | postgres | 16401  | public  | pg_stat_get_update_req_per_user        |     2 |            0
     10 | postgres | 16402  | public  | pg_stat_get_delete_req_per_user        |     2 |            0
     10 | postgres | 16403  | public  | pg_stat_get_truncate_req_per_user      |     2 |            0
     10 | postgres | 16404  | public  | pg_stat_get_grants_given_per_user      |     2 |            0
  16444 | u1       | 16448  | public  | p1                                     |     1 |            0
(12 rows)

Both tables now include rows corresponding to the operations of the u1 user: two inserts and a read of the table and one execution of the procedure.

Now let's look at the last-use statistics. We will be able to see timestamps showing when the user performed the inserts and the read.

postgres=# select * from pg_stat_all_tables_last_usage;
 userid | username | nspname | relid | relname |           last_read           |         last_insert          | last_update | last_delete | last_truncate
--------+----------+---------+-------+---------+-------------------------------+------------------------------+-------------+-------------+---------------
  16444 | u1       | public  | 16445 | t1      | 2024-11-30 01:06:24.578642+03 | 2024-11-30 01:06:17.03442+03 |             |             |
(1 row)

Let's extend this statistics with a read by a superuser:

postgres=# select * from t1;
 val
-----
   1
   2
(2 rows)
postgres=# select * from pg_stat_all_tables_last_usage;
 userid | username | nspname | relid | relname |           last_read           |         last_insert          | last_update | last_delete | last_truncate
--------+----------+---------+-------+---------+-------------------------------+------------------------------+-------------+-------------+---------------
     10 | postgres | public  | 16445 | t1      | 2024-11-30 01:09:29.994188+03 |                              |             |             |
  16444 | u1       | public  | 16445 | t1      | 2024-11-30 01:06:24.578642+03 | 2024-11-30 01:06:17.03442+03 |             |             |
(2 rows)

Let's make sure that the last_read timestamp gets updated:

postgres=# select * from t1;
 val
-----
   1
   2
(2 rows)
postgres=# select * from pg_stat_all_tables_last_usage;
 userid | username | nspname | relid | relname |           last_read           |         last_insert          | last_update | last_delete | last_truncate
--------+----------+---------+-------+---------+-------------------------------+------------------------------+-------------+-------------+---------------
     10 | postgres | public  | 16445 | t1      | 2024-11-30 01:10:28.122489+03 |                              |             |             |
  16444 | u1       | public  | 16445 | t1      | 2024-11-30 01:06:24.578642+03 | 2024-11-30 01:06:17.03442+03 |             |             |
(2 rows)

Now let's consider the statistics on unused privileges. Since there can be quite a lot of objects, users, and privileges, let's put everything related to this example in a separate schema to make it easier to filter the future result. We create a schema and a table in it, grant access on the table to a certain group role, and grant membership in this group role to a specific user:

postgres=# create schema shops;
CREATE SCHEMA
postgres=# create table shops.buildings();
CREATE TABLE
postgres=# create role manager;
CREATE ROLE
postgres=# grant all on schema shops to manager;
GRANT
postgres=# grant all on shops.buildings to manager;
GRANT
postgres=# create user vasya;
CREATE ROLE
postgres=# grant manager to vasya;
GRANT ROLE

Let's connect to the database as this user and query the table:

postgres=# \c - vasya
You are now connected to database "postgres" as user "vasya".
postgres=> select * from shops.buildings;
--
(0 rows)

Now let's switch to the superuser and look at the statistics on privileges:

postgres=> \c - postgres
You are now connected to database "postgres" as user "postgres".
postgres=# select * from pgpro_usage_stats_privileges_usage where usename='vasya' and nspname='shops';
 usename |  access  | nspname | targetname | provider | grantee |   kind   | used
---------+----------+---------+------------+----------+---------+----------+------
 vasya   | INSERT   | shops   | buildings  | manager  | manager | RELATION | f
 vasya   | SELECT   | shops   | buildings  | manager  | manager | RELATION | t
 vasya   | UPDATE   | shops   | buildings  | manager  | manager | RELATION | f
 vasya   | DELETE   | shops   | buildings  | manager  | manager | RELATION | f
 vasya   | TRUNCATE | shops   | buildings  | manager  | manager | RELATION | f
(5 rows)

These statistics show that the user vasya has full access to the shops.buildings table, and he got all the access privileges indirectly, as a memeber of the manager role. It is also clear that among the privileges, vasya only used SELECT. Note also that the statistics on privileges do not show superuser privileges: evidently, superuser has full access.

FAQ