Tische, die während der letzten Periode zugegriffen werden
-
16-10-2019 - |
Frage
Ich möchte überprüfen, welche Tabellen während eines bestimmten Zeitraums aktualisiert wurden, beispielsweise in der absteigenden Reihenfolge der Zugriffszeit pro Tabelle.
Wie kann ich das für Postgresql bekommen?
Lösung
Sie können einige Informationen über die letzte Änderung zu einer Tabelle mit erhalten xmin
, z.B:
select max(xmin::text::bigint) from t;
Aber Sie müssen sich bewusst sein von vielen Einschränkungen einschließlich Modulo und Wrack und Gefrorene Xids.
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;
--
Methode:
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
*/
Aufräumen:
drop schema stack cascade;
set role dba;
drop role stack;
Andere Tipps
Eine Vanille -Postgresql -Installation protokolliert keinen Zugriff auf Tabellen.
Wenn Sie brauchen, müssen Sie es selbst implementieren. Ich würde dafür Trigger verwenden. Ich benutze ein solches Setup für viele meiner Tische. Ich füge eine Spalte mit dem Namen hinzu log_up
Zu Tabellen möchte ich Updates verfolgen für:
log_up timestamptz DEFAULT current_timestamp;
Verwenden timestamptz
(timestamp with time zone
) die in Zeitzonen in allen Zeitzonen funktioniert:
Auslöserfunktion:
CREATE OR REPLACE FUNCTION trg_log_up()
RETURNS trigger AS
$func$
BEGIN
NEW.log_up := current_timestamp;
RETURN NEW;
END;
$func$
LANGUAGE plpgsql VOLATILE;
Abzug:
CREATE TRIGGER log_up
BEFORE UPDATE ON tbl
FOR EACH ROW EXECUTE PROCEDURE trg_log_up();
Es gibt ein paar verwandte Protokollierungsparameter Möglicherweise interessieren Sie sich zusätzlich. Wie log_connections
oder log_statement
.
Aktualisieren:Auch bedenken "Zeitstempel begehen" in Postgres hinzugefügt 9.5:
Fügen Sie allen Tabellen Trigger hinzu
Sie können ein Skript für alle aktuell vorhandenen Tabellen erstellen, indem Sie den Datenbankkatalog abfragen. Zum Beispiel, um die DDL -Anweisungen für alle Tabellen im Schema zu generieren 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
Kehrt zurück:
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();
...
Natürlich müssen sie alle eine Spalte haben log_up
vom Typ timestamptz
Erste. Sie können ein DDL -Skript erstellen, um die Spalte auf ähnliche Weise zu allen Tabellen hinzuzufügen.
Nur zuletzt protokollieren UPDATE
pro Tabelle
Wenn Sie nur an der letzten interessiert sind UPDATE
pro Tabelle ist eine einfachere Lösung. Hier ist eine Demo, wie man in einer zentralen Tabelle den Überblick behält:
CREATE TABLE lastup (
schema_name text
, tbl_name text
, ts timestamptz
, PRIMARY KEY (schema_name, tbl_name)
);
Abzug. Konsultieren Sie die Handbuch zu den besonderen Variablen Ich benutze:
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;
Dummy -Tisch zum Testen:
CREATE TABLE dummy (id int);
INSERT INTO dummy VALUES (1), (2), (3);
Geben Sie die Zeile für die Tabelle in der Protokolltabelle ein:
INSERT INTO lastup(schema_name, tbl_name) VALUES ('public', 'dummy');
Abzug. Beachten Sie, dass ich eine verwende AFTER
Abzug FOR EACH STATEMENT
(billiger). Mehr im Handbuch hier.
CREATE TRIGGER log_up
AFTER UPDATE ON dummy
FOR EACH STATEMENT EXECUTE PROCEDURE trg_lastup();
Prüfen:
UPDATE dummy
SET id = id + 5
WHERE id < 3;
Voilá:
SELECT * FROM lastup;
Oder, wenn Sie wollen leere Updates ausschließen (Nichts hat sich geändert), aber zu höheren Kosten, da mehrere aktualisierte Zeilen mehrere Protokoll -Updates auslösen:
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
Zu Trigger erstellen Verwenden Sie für alle Tabellen, die Sie in dieses Regime aufnehmen möchten, ein ähnliches DDL -Erstellungsskript wie oben.