これがいくつか修正された後、これが私の結論です。これは、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;
「diffing」スキーマではなく、適切なスキーマ移行ツールを使用する必要があります。その後、ツールは適用対象を知ることになります。 LiquibaseまたはFlywayを見てください –
@a_horse_with_no_name、ヒントありがとうございます。私はLiquibaseを参照していたが、Flywayについては知らなかった。私はあなたに同意し、アプリケーション環境全体の方向性を変えたいと考えていますが、存在することが知られている相違点と今後の展開を調整するための相違点の概要を見たいチームのメンバーがあります。 – Dan