Pregunta

Quiero verificar qué tablas se han actualizado durante un período determinado, por ejemplo, en orden descendente de tiempo de acceso por tabla.

¿Cómo puedo obtener eso para PostgreSQL?

¿Fue útil?

Solución

Puede obtener información sobre el último cambio a una tabla con xmin, p.ej:

select max(xmin::text::bigint) from t;

Pero debes ser consciente de muchas advertencias incluido módulo y envoltura y xids congelados.

Testbed:

set role dba;
create role stack;
grant stack to dba;
create schema authorization stack;
set role stack;
--
create or replace function f(p_schema in text, p_table in text) 
                  returns integer language plpgsql immutable as $$
declare
  n integer;
begin
  execute 'select max(xmin::text::bigint) from '||p_schema||'.'||p_table into n;
  return n;
end;$$;
--
create table foo as select generate_series(1, 100) as id;
create table bar as select generate_series(1, 100) as id;
create table baz as select generate_series(1, 100) as id;
--

método:

select table_name, f(table_schema, table_name)
from information_schema.tables
where table_schema='stack'
order by 2 desc;
/*
 table_name |   f
------------+--------
 baz        | 784657
 bar        | 784656
 foo        | 784655
*/
--
update foo set id=id+1 where id=100;
--
select table_name, f(table_schema, table_name)
from information_schema.tables
where table_schema='stack'
order by 2 desc;
/*
 table_name |   f
------------+--------
 foo        | 784658
 baz        | 784657
 bar        | 784656
*/

limpiar:

drop schema stack cascade;
set role dba;
drop role stack;

Otros consejos

Una instalación de Vanilla PostgreSQL no registra acceso a las tablas.

Si necesita que tenga que implementarlo usted mismo. Yo usaría desencadenantes para eso. Utilizo una configuración como esta para muchas de mis tablas. Agrego una columna con nombre log_up a las tablas quiero rastrear actualizaciones para:

log_up timestamptz DEFAULT current_timestamp;

Usar timestamptz (timestamp with time zone) que funciona a través de zonas horarias:

Función de activación:

CREATE OR REPLACE FUNCTION trg_log_up()
  RETURNS trigger AS
$func$
BEGIN
   NEW.log_up := current_timestamp;
   RETURN NEW;
END;
$func$
  LANGUAGE plpgsql VOLATILE;

Generar:

CREATE TRIGGER log_up
BEFORE UPDATE ON tbl
FOR EACH ROW EXECUTE PROCEDURE trg_log_up();

Hay un par de relacionados Parámetros de registro Puede estar interesado en además. Me gusta log_connections o log_statement.

Actualizar:También considerar "cometer marcas de tiempo" agregado en Postgres 9.5:

Agregar disparador a todas las tablas

Puede crear un script para todas las tablas existentes actualmente consultando el catálogo de la base de datos. Por ejemplo, para generar las declaraciones DDL para todas las tablas en el esquema public:

SELECT string_agg(format('CREATE TRIGGER log_up BEFORE UPDATE ON %s '
                         'FOR EACH ROW EXECUTE PROCEDURE trg_log_up();'
                        , c.oid::regclass), E'\n')
FROM   pg_namespace n
JOIN   pg_class     c ON c.relnamespace = n.oid
WHERE  n.nspname = 'public';
-- AND c.relname ~~* '%tbl%' -- to filter tables by name

Devoluciones:

CREATE TRIGGER log_up BEFORE UPDATE ON tbl1 FOR EACH ROW EXECUTE PROCEDURE trg_log_up();
CREATE TRIGGER log_up BEFORE UPDATE ON tbl2 FOR EACH ROW EXECUTE PROCEDURE trg_log_up();
CREATE TRIGGER log_up BEFORE UPDATE ON tbl3 FOR EACH ROW EXECUTE PROCEDURE trg_log_up();
...

Por supuesto, todos necesitan tener una columna log_up de tipo timestamptz primero. Puede crear un script DDL para agregar la columna a todas las tablas de manera similar.


Registro solo dura UPDATE por mesa

Si solo estás interesado en el último UPDATE Por tabla, una solución más simple servirá. Aquí hay una demostración de cómo realizar un seguimiento en una mesa centralizada:

CREATE TABLE lastup (
  schema_name text
, tbl_name text
, ts timestamptz
, PRIMARY KEY (schema_name, tbl_name)
);

Generar. Consultar el Manual sobre las variables especiales Yo suelo:

CREATE OR REPLACE FUNCTION trg_lastup()
  RETURNS trigger AS
$func$
BEGIN
   UPDATE lastup
   SET    ts = current_timestamp
   WHERE  schema_name = TG_TABLE_SCHEMA
   AND    tbl_name    = TG_TABLE_NAME;

   RETURN NULL;   -- For AFTER trigger irrelevant
END
$func$  LANGUAGE plpgsql;

Mesa ficticia para la prueba:

CREATE TABLE dummy (id int);
INSERT INTO dummy VALUES (1), (2), (3);

Ingrese la fila para la tabla en la tabla de registro:

INSERT INTO lastup(schema_name, tbl_name) VALUES ('public', 'dummy');

Generar. Tenga en cuenta que uso un AFTER generar FOR EACH STATEMENT (más económico). Más en el manual aquí.

CREATE TRIGGER log_up
AFTER UPDATE ON dummy
FOR EACH STATEMENT EXECUTE PROCEDURE trg_lastup();

Prueba:

UPDATE dummy
SET    id = id + 5
WHERE  id < 3;

Voilá:

SELECT * FROM lastup;

O, si quieres excluir actualizaciones vacías (Nada cambió), pero a un costo más alto porque múltiples filas actualizadas activan múltiples actualizaciones de registro:

CREATE OR REPLACE FUNCTION trg_lastup()
  RETURNS trigger AS
$func$
BEGIN
   IF OLD IS DISTINCT FROM NEW THEN  -- check for changes
      UPDATE lastup
      SET    ts = current_timestamp
      WHERE  schema_name = TG_TABLE_SCHEMA
      AND    tbl_name    = TG_TABLE_NAME;
   END IF;

   RETURN NULL;  -- For AFTER trigger!
END;
$func$  LANGUAGE plpgsql;

CREATE TRIGGER log_up
AFTER UPDATE ON dummy
FOR EACH ROW EXECUTE PROCEDURE trg_lastup();  -- per ROW instead of STATEMENT

A Crear desencadenantes Para todas las tablas que desea incluir en este régimen, use un script de creación DDL similar como arriba.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a dba.stackexchange
scroll top