Tabelle accessibili durante l'ultimo periodo di
-
16-10-2019 - |
Domanda
Voglio controllare che le tabelle sono state aggiornate nel corso di un determinato periodo, per esempio in ordine di tempo di accesso per ogni tabella decrescente.
Come posso ottenere che per PostgreSQL?
Soluzione
È possibile ottenere alcune informazioni circa l'ultima modifica a una tabella con xmin
, ad esempio:
select max(xmin::text::bigint) from t;
Ma è necessario essere consapevoli di molti avvertimenti compreso modulo e avvolgente e XID congelati .
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;
--
Metodo:
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
*/
cleanup:
drop schema stack cascade;
set role dba;
drop role stack;
Altri suggerimenti
Un vaniglia PostgreSQL non registra l'accesso alle tabelle.
Se avete bisogno di avere per la sua attuazione da soli. Vorrei utilizzare i trigger per questo. Io uso una configurazione simile per molti dei miei tavoli. Aggiungo una colonna denominata log_up
alle tabelle voglio tenere traccia degli aggiornamenti per:
log_up timestamptz DEFAULT current_timestamp;
Usa timestamptz
(timestamp with time zone
) che opera attraverso i fusi orari:
funzione trigger:
CREATE OR REPLACE FUNCTION trg_log_up()
RETURNS trigger AS
$func$
BEGIN
NEW.log_up := current_timestamp;
RETURN NEW;
END;
$func$
LANGUAGE plpgsql VOLATILE;
trigger:
CREATE TRIGGER log_up
BEFORE UPDATE ON tbl
FOR EACH ROW EXECUTE PROCEDURE trg_log_up();
Ci sono un paio di relativi parametri di registrazione si può essere interessati in aggiunta. Come log_connections
o log_statement
.
Aggiornamento: Considera anche "commit timestamp" aggiunto in Postgres 9.5 :
Add grilletto per tutte le tabelle
È possibile creare uno script per tutte le tabelle attualmente esistenti interrogando il catalogo di database. Per esempio per generare le istruzioni DDL per tutte le tabelle del public
schema:
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
Returns:
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();
...
Naturalmente, tutti hanno bisogno di avere un log_up
colonna di tipo timestamptz
prima. È possibile creare uno script DDL per aggiungere la colonna a tutte le tabelle in un modo simile.
solo Log ultima UPDATE
per tabella
Se si è interessati solo nell'ultimo UPDATE
per tavolo, una soluzione più semplice farà. Ecco una demo di come tenere traccia in una tabella centralizzata:
CREATE TABLE lastup (
schema_name text
, tbl_name text
, ts timestamptz
, PRIMARY KEY (schema_name, tbl_name)
);
trigger. Consultare il manuale sulle variabili speciali io uso:
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;
Tavolo Dummy per il test:
CREATE TABLE dummy (id int);
INSERT INTO dummy VALUES (1), (2), (3);
Inserisci riga per la tabella nella tabella di log:
INSERT INTO lastup(schema_name, tbl_name) VALUES ('public', 'dummy');
trigger. Si noti che io uso un AFTER
FOR EACH STATEMENT
grilletto (più economico). Più nel manuale qui.
CREATE TRIGGER log_up
AFTER UPDATE ON dummy
FOR EACH STATEMENT EXECUTE PROCEDURE trg_lastup();
Prova:
UPDATE dummy
SET id = id + 5
WHERE id < 3;
voilà:
SELECT * FROM lastup;
o , se si desidera escludere aggiornamenti vuote (nulla è cambiato), ma ad un costo più elevato perché più aggiornato righe innescare più aggiornamenti di 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
creare i trigger per tutte le tabelle che si desidera includere in questo regime, utilizzare uno script di creazione DDL simile come sopra.