Tablas accedidas durante el último período
-
16-10-2019 - |
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?
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.