2016-07-31 1 views
2

Unten ist eine großartige Funktion, um die tatsächliche Anzahl aller Tabellen in der PostgreSQL-Datenbank zu überprüfen. Ich fand es here.Wie aktualisiert man die Ergebnisse des EXECUTE-Formatblocks in Funktion (PostgreSQL)

Von meinem lokalen Test scheint es, dass die Funktion das Ergebnis nur zurückgibt, nachdem alle 100 Tabellen gezählt wurden.

Ich versuche, es praktischer zu machen. Wenn wir das Ergebnis jeder Tabellenzählung speichern könnten, sobald es mit der Tabelle fertig ist, können wir den Fortschritt aller Zähljobs überprüfen, anstatt auf das Ende zu warten.

Ich denke, wenn ich das Ergebnis in dieser Funktion sofort nach Abschluss der ersten Tabelle aktualisieren könnte, wird es für meine Anforderung groß sein.

Können Sie mich wissen lassen, wie ich das Ergebnis in die Tabelle aktualisieren kann, nachdem diese Funktion das Zählen der ersten Tabelle beendet hat?

CREATE FUNCTION rowcount_all(schema_name text default 'public') 
    RETURNS table(table_name text, cnt bigint) as 
$$ 
declare 
table_name text; 
begin 
    for table_name in SELECT c.relname FROM pg_class c 
    JOIN pg_namespace s ON (c.relnamespace=s.oid) 
    WHERE c.relkind = 'r' AND s.nspname=schema_name 
    ORDER BY c.relname 
    LOOP 
    RETURN QUERY EXECUTE format('select count(*) from %I.%I', 
     table_name, schema_name, table_name); 
    END LOOP; 
end 
$$ language plpgsql; 

-- Query 

WITH rc(schema_name,tbl) AS (
    select s.n,rowcount_all(s.n) from (values ('schema1'),('schema2')) as s(n) 
) 
SELECT schema_name,(tbl).* FROM rc; 

Aktualisiert

habe ich beschlossen, ein Shell-Skript zu verwenden, um die Funktion unten als Hintergrundprozess zu laufen. Die Funktion würde eine Verarbeitungsprotokolldatei erzeugen, so dass ich den aktuellen Prozess überprüfen kann.

Antwort

1

Ich denke, Ihre Idee ist gut, aber ich denke auch nicht, dass es "out of the box" auf PostgreSQL funktioniert. Ich bin keineswegs der Experte dafür, aber die Art und Weise, wie MVCC auf PostgreSQL funktioniert, macht im Grunde die gesamte DML in dem, was am besten als temporärer Raum verstanden werden kann, und wenn dann alles wie erwartet funktioniert, verschiebt es alles Am Ende.

Dies hat viele Vorteile, vor allem, wenn jemand Tabellen aktualisiert, verhindert es nicht, dass andere von denselben Tabellen abfragen.

Wenn dies Oracle wäre, denke ich, Sie könnten dies innerhalb der gespeicherten Proc mit commit, erreichen, aber das ist nicht Oracle. Und um fair zu sein, Oracle erlaubt es nicht, dass Kürzungen in einem gespeicherten Proc zurückgerollt werden, so wie es PostgreSQL tut, also gibt es Gibt und Takes.

Noch einmal, ich bin nicht der Experte, also, wenn ich ein oder zwei Details vermasselt habe, fühlen Sie sich frei, mich zu korrigieren.

Also, zurück zur Lösung. Eine Möglichkeit, COULD dies zu erreichen ist, Ihren Server als Remote-Server einzurichten. So etwas wie dies funktionieren würde:

CREATE SERVER pgprod 
FOREIGN DATA WRAPPER dblink_fdw 
OPTIONS (dbname 'postgres', host 'localhost', port '5432'); 

Angenommen, Sie haben eine Tabelle, die die Tabellen und Zählungen speichert:

create table table_counts (
    table_name text not null, 
    record_count bigint, 
    constraint table_counts_pk primary key (table_name) 
); 

Wäre es nicht für Ihren Wunsch, diese Ergebnisse zu sehen, wie sie auftreten, so etwas wie dies würde arbeiten, für ein einzelnes Schema. Es ist einfach genug, um diese alle Schemata zu machen, so ist dies zur Erläuterung:

CREATE or replace FUNCTION rowcount_all(schema_name text) 
    returns void as 
$$ 
declare 
rowcount integer; 
tablename text; 
begin 
    for tablename in SELECT c.relname FROM pg_class c 
    JOIN pg_namespace s ON (c.relnamespace=s.oid) 
    WHERE c.relkind = 'r' AND s.nspname=schema_name 
    ORDER BY c.relname 
    LOOP 
    EXECUTE 'select count(*) from ' || schema_name || '.' || tablename into rowcount; 
    insert into table_counts values (schema_name || '.' || tablename, rowcount) 
    on conflict (table_name) do 
    update set record_count = rowcount; 
    END LOOP; 
end 
$$ language plpgsql; 

(dies setzt voraus, 9.5 oder höher - wenn nicht, Ihre eigene Upsert Hand rollen).

Da jedoch Sie Updates in Echtzeit auf den Tisch wollen, könnten Sie dann setzen die gleiche Upsert in einen dblink Ausdruck:

perform dblink_exec('pgprod', ' 
     << your upsert statement here >> 
    '); 

Natürlich ist die Formatierung des SQL innerhalb der DBlink ist jetzt ein wenig besonders schwierig, aber die Oberseite ist, sobald Sie es nageln, Sie können die Funktion im Hintergrund laufen lassen und die Tabelle abfragen, während es läuft, um die dynamischen Resultate zu sehen.

Ich würde das gegen die Notwendigkeit abwägen, wirklich die Informationen in Echtzeit zu haben.

+0

Wunderbarer Ansatz. Sie meinen, dass ich ohne DBlink-Implementierung die Tabelle counts nicht dynamisch abfragen kann, wie es nach Abschluss aller Zähljobs geschehen würde? – Sigularity

+0

Meine externe Anwendung konnte alle 10 Sekunden Tabelle_Counts-Tabellen abfragen, also denke ich, dass DBlink nicht implementiert werden muss? – Sigularity

+0

Ich frage vielleicht nach 'autonome Transaktion' in der Funktion. Ich kann die Tabelle nicht abfragen, während die Funktion funktioniert. – Sigularity

Verwandte Themen