2016-07-31 7 views
2

以下は、PostgreSQLデータベースのすべてのテーブルの実数をチェックする素晴らしい関数です。私はそれを見つけたhere関数内のEXECUTEフォーマットブロックの結果を更新する方法(PostgreSQL)

私のローカルテストでは、100個のテーブルをすべてカウントした後にのみ、すべての結果が返されるようです。

私はより実用的にしようとしています。テーブルを終了するとすぐに各テーブルの結果を保存することができれば、終了を待つのではなく、すべてのカウントジョブの進行状況を確認できます。

私は最初のテーブルを終了した直後にこの関数の結果を更新できたら、それは私の必要条件にとって素晴らしいことだと思います。

この関数が最初のテーブルのカウントを終了した後、結果をテーブルに更新する方法を教えてください。

を更新しました

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; 

私は、バックグラウンドプロセスとして以下の機能を実行するためにシェルスクリプトを使用することを決定しました。この関数は処理ログファイルを生成するので、現在のプロセスを確認できます。

答えて

1

あなたのアイデアは良いと思いますが、私はPostgreSQLの "すぐに使える"とは思えません。私は決してこれの専門家ではありませんが、MVCCがPostgreSQLで動作する方法は、基本的にすべてのDMLを一時的なスペースとして理解することです。そして、すべてが期待どおりに動作する場合は、最後に。

これには多くの利点があります。特に、誰かがテーブルを更新しているときに、他の人が同じテーブルからクエリを実行することを防ぐことはできません。

これがOracleの場合は、commit,を使用してストアドプロシージャ内でこれを実行できると思いますが、これはOracleではありません。そして公平であるために、OracleはPostgreSQLのようにストアドプロシージャ内で切り詰めをロールバックすることはできないので、giveとtakesがあります。

もう一度、私は専門家ではないので、もし私が1つまたは2つの詳細を台無しにしてしまったら、私を修正してください。

だから、ソリューションに戻ってください。 1つの方法は、がこれを達成するために、サーバーをリモートサーバーとしてセットアップすることです。このような何かが働くだろう:

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

あなたは、テーブルとカウントを格納するテーブルを持っていると仮定すると:

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

は、これらの結果が発生したときに、このようなものは希望を参照するにはあなたの欲求のためにそれをされませんでした単一のスキーマに対して作業することができます。これは、このすべてのスキーマを作ることは簡単ですので、これは例示のためのものである:

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; 

(これは9.5以上を前提としている - そうでない場合は、あなた自身のアップサートを手で転がし)。今もちろん

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

DBLINK内のSQLのフォーマットがある少し:あなたがテーブルにリアルタイムの更新をしたいので、

しかし、あなたはその後、データベース・リンク式に、同じアップサートを入れることができます余計なトリッキーですが、いったんそれを釘付けにすれば、バックグラウンドでこの機能を実行し、実行中にテーブルを照会して動的結果を確認することができます。

実際に情報をリアルタイムに取得する必要性と比較して重いと思います。

+0

すばらしいアプローチ。 DBlinkの実装がなければ、すべてのカウントジョブが完了した後にコミットするように、table_countsを動的にクエリできないということですか? – Sigularity

+0

私の外部アプリケーションは、10秒ごとにtable_countsテーブルを照会できたので、DBlinkを実装する必要はありませんか? – Sigularity

+0

私はこの機能で「自律的なトランザクション」について質問しているかもしれません。関数が動作している間はテーブルを照会できません。 – Sigularity