2017-01-05 7 views
2

私は、すべてのオブジェクトが配備されたことを検証する簡単な方法を望むチームメイトに "クエリ"を提供することが任されています。 QAまたはProduction PostgreSQLデータベースサーバ。異なるPostgreSQLデータベースにデプロイされたDDLオブジェクトまたは関数のリストを生成する方法

具体的には、リクエスタは、すべてのテーブル、関数、シーケンス、インデックス、ビュー、スキーマ、およびトリガが各環境に存在していること、および/または新しいアプリケーションが配備されたときに。

これまでのところ、私が発見したインデックスを識別するためのクエリと、彼らは、他のオブジェクトのINFORMATION_SCHEMAのテーブルを照会することができます(Position of the column in the index)であり、およびスキーマの完全な差分を生成するためのツールについて学んできたコラム/列の順序(How to check difference between two databases in PostgreSQL?) 。有用なツールapgdiffは、データベースを同期させるためのSQL出力を提供しますが、異なるオブジェクトの要約を取得する方法は見当たりませんでした。要求者はスプレッドシートを探しています。すべてのオブジェクトが存在することが確認されると、apgdiffまたは他のツールを使用して、完全なテーブル定義と関数&トリガコードが同一であることをさらに調べることができますが、それは後の作業になります。

インデックスや関数パラメータを使用しないこの最初の試みは、各環境で個別に実行するUNIONクエリですが、すべての環境に対してこれを実行し、結果を結合するコードも必要です。

select routine_name as object_name, routine_schema as schema_name, 'routine' as object_type, 'yes' as object_exists from information_schema.routines where routine_schema in ('shema1','schema2','schema3') union 
select schema_name as object_name, schema_name as schema_name, 'schema' as object_type, 'yes' as object_exists from information_schema.schemata where schema_name in ('shema1','schema2','schema3') union 
select sequence_name as object_name, sequence_schema as schema_name, 'sequence' as object_type, 'yes' as object_exists from information_schema.sequences where sequence_schema in ('shema1','schema2','schema3') union 
select table_name as object_name, table_schema as schema_name, 'table' as object_type, 'yes' as object_exists from information_schema.tables where table_schema in ('shema1','schema2','schema3') union 
select trigger_name as object_name, trigger_schema as schema_name, 'trigger' as object_type, 'yes' as object_exists from information_schema.triggers where trigger_schema in ('shema1','schema2','schema3') union 
select table_name as object_name, table_schema as schema_name, 'view' as object_type, 'yes' as object_exists from information_schema.views where table_schema in ('shema1','schema2','schema3') 
order by object_type, schema_name, object_name; 
+1

「diffing」スキーマではなく、適切なスキーマ移行ツールを使用する必要があります。その後、ツールは適用対象を知ることになります。 LiquibaseまたはFlywayを見てください –

+0

@a_horse_with_no_name、ヒントありがとうございます。私はLiquibaseを参照していたが、Flywayについては知らなかった。私はあなたに同意し、アプリケーション環境全体の方向性を変えたいと考えていますが、存在することが知られている相違点と今後の展開を調整するための相違点の概要を見たいチームのメンバーがあります。 – Dan

答えて

0

これがいくつか修正された後、これが私の結論です。これは、pgAdmin、psqlなどの1つのセッションから3つの異なる環境を照会するためにdblink拡張子(前提条件として必要とされ、この場合は "extension_data"というスキーマにインストールされています)を使用します。出力には、オブジェクト名、 3つの環境のどれにオブジェクトがロードされているかを示します。索引の場合、索引の重要な部分であり、システム生成名は理論的に異なる可能性があるため、表名、タイプ(USING句)、および名前の代わりに順序付き列リストが含まれていました。また、「object_info」の列には、簡単にアクセスできるように存在しないインデックス用のCREATE INDEXコマンドと、クエリされるさまざまなpg_settings設定の説明が含まれています。

do $$ 
-- Two changes are needed below: 
--  (1) the schema list needs to be updated 
--  (2) the dblink connection information for each environment needs to be updated 
-- Execute this in pgadmin while connected to one of the environments. If the username and 
-- password are the same in all three environments then they do not need to be listed in 
-- the dblink connection strings below 
declare 
    rc bigint := 0; 
    r RECORD; 
    -- Necessary change #1: put the schemas you care about here 
    v_schema_list text := '''schema1'',''schema2'',''schema3'',''schema4'''; 
    -- This is a large query looking at database settings, functions (routines), schemas, sequences, tables, triggers, views, and indexes 
    -- For functions, the parameter list is important since the same function name can exist with a different number of parameters 
    --  or the parameters in a different order. This query is not looking at parameter defaults. 
    -- For indexes, the name of the index isn't important to a functioning system, but the type of index and column order is 
    -- For tables, this only looks for the existence of the table, not the column order nor constraints, but those could be added later 
    v_sql text := 'select name||'' = ''||setting as object_name, ''setting'' as object_type, category||'': ''||short_desc as object_info 
          from pg_settings 
        union 
        select routine_schema||''.''||routine_name||''(''||coalesce(string_agg(parameters.parameter_name||'' ''||parameters.data_type,'', ''),'''')||'')'' as object_name 
         , ''routine'' as object_type 
         , ''''::text as object_info 
         from information_schema.routines 
         left join lateral 
          (select parameter_name, parameters.data_type, parameters.ordinal_position 
          from information_schema.parameters 
          where parameters.specific_schema = routines.specific_schema 
          and parameters.specific_name = routines.specific_name 
          order by ordinal_position) parameters 
          on true 
         where routine_schema in ('||v_schema_list||') 
         group by routine_name, routine_schema 
        union 
        select schema_name||''.''||schema_name as object_name, ''schema'' as object_type, ''''::text as object_info 
         from information_schema.schemata where schema_name in ('||v_schema_list||') 
        union 
        select sequence_schema||''.''||sequence_name as object_name, ''sequence'' as object_type, ''''::text as object_info 
         from information_schema.sequences where sequence_schema in ('||v_schema_list||') 
        union 
        select table_schema||''.''||table_name as object_name, ''table'' as object_type, ''''::text as object_info 
         from information_schema.tables where table_schema in ('||v_schema_list||') 
        union 
        select trigger_schema||''.''||trigger_name as object_name, ''trigger'' as object_type, ''''::text as object_info 
         from information_schema.triggers where trigger_schema in ('||v_schema_list||') 
        union 
        select table_schema||''.''||table_name as object_name, ''view'' as object_type, ''''::text as object_info 
         from information_schema.views where table_schema in ('||v_schema_list||') 
        union 
        select substring(indexdef,3+position(''ON'' in indexdef)) as object_name, ''index'' as object_type, indexdef as object_info 
         from pg_indexes where schemaname in ('||v_schema_list||') 
        order by object_type, object_name; '; 
begin 
    drop table if exists object_list; 
    drop table if exists object_comparison; 
    create temp table object_list (object_name text, object_type text, object_info text, environment text); 

    for r in 
     -- Necessary change #2: update connection information for each database here 
     select 'prod' as conn, 'dbname=your_prod_db_name port=5432 host=your_prod_server username=your_prod_user password=your_prod_password' as conn_string union 
     select 'qa' as conn, 'dbname=your_qa_db_name port=5432 host=your_qa_server username=your_qa_user password=your_qa_password' as conn_string union 
     select 'dev' as conn, 'dbname=your_dev_db_name port=5432 host=your_dev_server username=your_dev_user password=your_dev_password' as conn_string 
    loop 
     begin 
      perform extension_data.dblink_disconnect(r.conn);  
     exception when others then 
      null; 
     end; 
     perform extension_data.dblink_connect(r.conn, r.conn_string); 

     perform extension_data.dblink_open(r.conn, 'object_list',v_sql); 
     GET CURRENT DIAGNOSTICS rc := ROW_COUNT; 

     while rc > 0 loop 
      insert into object_list 
       SELECT *, r.conn as environment 
       FROM extension_data.dblink_fetch(r.conn, 'object_list', 500) AS (object_name text, object_type text, object_info text); 
      GET CURRENT DIAGNOSTICS rc := ROW_COUNT; 
     end loop; 

     perform extension_data.dblink_close(r.conn, 'object_list'); 

     perform extension_data.dblink_disconnect(r.conn);  
    end loop; 

    create temp table object_comparison as (
     select coalesce(dev.object_name,coalesce(qa.object_name,prod.object_name)) as object_name 
      , coalesce(dev.object_type,coalesce(qa.object_type,prod.object_type)) as object_type 
      , dev.environment as dev 
      , qa.environment as qa 
      , prod.environment as prod 
      , coalesce(prod.object_info,coalesce(qa.object_info,dev.object_info)) as object_info 
     from (select * from object_list where environment = 'dev') dev 
     full outer join (select * from object_list where environment = 'qa') qa 
      on dev.object_name = qa.object_name 
      and dev.object_type = qa.object_type 
     full outer join (select * from object_list where environment = 'prod') prod 
      on coalesce(dev.object_name,qa.object_name) = prod.object_name 
      and coalesce(dev.object_type,qa.object_type) = prod.object_type 
    ); 
end; 
$$ language plpgsql; 

select * from object_comparison where dev is null or qa is null or prod is null; 
関連する問題