CREATE TABLE table1_swap LIKE table1
を使用してswap
テーブルを作成する一連のETLジョブがあります。 table1_swap
の入力を高速化するために、インデックスを含めません。しかし、読み込みが完了したら、新しく作成されたテーブルにそれらのインデックスを再適用する必要があります。これらのインデックスはこれらのETLジョブのスコープ外で作成されるため、必要がない場合はCREATE INDEX
呼び出しをハードコーディングする必要はありません。
あるテーブルから別のテーブルに一連のインデックスを「転送」または「コピー」することは可能ですか?
Postgresシステムカタログから各インデックスの完全なDDLステートメントを取得できます。
次は、単一のテーブルのすべてのCREATE
インデックスステートメントを取得します。
select pg_get_indexdef(idx.oid)||';'
from pg_index ind
join pg_class idx on idx.oid = ind.indexrelid
join pg_class tbl on tbl.oid = ind.indrelid
left join pg_namespace ns on ns.oid = tbl.relnamespace
where tbl.relname = 'your_table_name'
and ns.nspname = 'your_table_schema';
出力をスクリプトにスプールし、データをコピーしてテーブル名を交換した後で実行できます。
すべてのインデックス定義を取得するには、システムカタログ情報関数 pg_get_indexdef(index_oid)
のように使用できます @ a_horseはすでに提供されています のように。
ただし、regclass
パラメータを使用すると、クエリをかなり簡単にすることができます。 tbl
スキーマのpublic
というテーブルの場合:
_SELECT pg_get_indexdef(indexrelid) || ';' AS idx
FROM pg_index
WHERE indrelid = 'public.tbl'::regclass; -- optionally schema-qualified
_
これには、allインデックスが含まれます:PK、部分的、機能的、一意、特別な演算子クラスなど。
regclass
の詳細:
まだこれで作業できません。古いテーブル名を新しいものに置き換える必要があります-文字列の誤検出(テーブル名と一致する列名など)を置き換えたくない場合:
Postgresのデフォルトの命名規則を使用している場合、インデックス定義は次のようになります。
_CREATE INDEX tbl_tbl_id_idx ON tbl USING btree (tbl_id);
CREATE INDEX tbl_people_gin_idx ON tbl
USING gin (((data -> 'people'::text)) jsonb_path_ops);
CREATE INDEX tbl_comecol_nonull_idx ON tbl
USING btree (somecol) WHERE (cutblade IS NOT NULL);
_
元のテーブル名をすべて太字にしました。置き換えたくないthree誤検知(列名またはインデックス名の一部)に注意してください。
このクエリは問題なく動作するはずですが、-verifyこれは実際のインデックスに対して自分で実行することです!
_SELECT regexp_replace(regexp_replace(
pg_get_indexdef(indexrelid)
, 'tbl', 'tbl1')
, ' ON tbl ', ' ON tbl1 ')
|| ';' AS idx
FROM pg_index
WHERE indrelid = 'public.tbl'::regclass;
_
最初のreplace()
は、名前の最初の一致のみを置き換えます(特に指示がない限り)。 2番目のregexp_preplace()
はより具体的で、実際のテーブル名のみを置き換えます。
与えられた例では、次のようになります。
_CREATE INDEX tbl1_tbl_id_idx ON tbl1 USING btree (tbl_id);
CREATE INDEX tbl1_people_gin_idx ON tbl1
USING gin (((data -> 'people'::text)) jsonb_path_ops);
CREATE INDEX tbl1_somecol_nonull_idx ON tbl1
USING btree (somecol) WHERE (cutblade IS NOT NULL);
_
ただし、非標準のテーブル名、スキーマ、または_search_path
_設定についてはまだ考慮していません。これらはすべて以下の関数に組み込まれています。
命名方式に自信がある場合は、次のことができます完全に自動化:
_CREATE OR REPLACE FUNCTION f_copy_idx(_tbl text, _tbl1 text
, _sch text = 'public', _sch1 text = 'public')
RETURNS void AS
$func$
DECLARE
_full_tbl text := format('%I.%I', _sch, _tbl);
_full_tbl1 text := format('%I.%I', _sch1, _tbl1);
BEGIN
-- RAISE NOTICE '%', -- for testing
EXECUTE
(SELECT string_agg(
regexp_replace(regexp_replace(
pg_get_indexdef(indexrelid)
, _tbl, _tbl1)
, ' ON ' || _full_tbl || ' ', ' ON ' || _full_tbl1 || ' ')
, '; ') AS idx
FROM pg_index
WHERE indrelid = _full_tbl::regclass);
END
$func$ LANGUAGE plpgsql SET search_path = '';
_
これは、二重引用符と異なるスキーマが必要な非標準のテーブル名にも対応しています。
スキーマで修飾されたテーブル名を強制するには、関数(_SET search_path = ''
_)内のsearch_pathをリセットします。これにより、設定に依存しない信頼性の高い結果が得られます。
スキーマパラメータ_'public'
_および__sch
_のデフォルト値として__sch1
_を追加しました。したがって、両方のテーブルがパブリックスキーマにある場合は、スキーマパラメータを単純に無視できます。
コール:
_SELECT f_copy_idx('mytbl', 'newtbl'); -- all in schema public
_
または、二重引用符と異なるスキーマを必要とするテーブル名の場合:
_SELECT f_copy_idx('old_TBL', 'table', 'public', 'New_SCHEmA');
_
SQL Fiddle 使用中の関数を示します。
それらを「コピー」することはできませんが、データベースのメタデータを使用して動的にDDLを生成し、それらを作成することができます。
SELECT 'CREATE '
|| CASE
WHEN i.indisunique THEN 'UNIQUE '
ELSE ''
END
|| 'INDEX '
|| nr.nspname
|| '.'
|| c2.relname
|| '_swap ON '
|| nr.nspname
|| '.'
|| c.relname
|| '_swap ( '
|| split_part ( split_part ( pg_catalog.pg_get_indexdef ( i.indexrelid, 0, true ), '(', 2 ), ')', 1 )
|| ' ) '
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_index i
ON ( c.oid = i.indrelid )
JOIN pg_catalog.pg_class c2
ON ( i.indexrelid = c2.oid )
JOIN pg_namespace nr
ON ( nr.oid = c.relnamespace )
WHERE nr.nspname = 'schema for table1'
AND c.relname = 'table1' ;
カイル、
恐らく、PostgreSQLのストレージ構造により、インデックスの単純なコピーは不可能です。 PostgreSQLは heap-structured tables と呼ばれるストレージメソッドを使用し、テーブルへのデータの挿入には保証された順序や位置はありません。
PostgreSQLが1つのテーブルレコードから別のテーブルレコードに、すべての行のすべてのバージョン、削除された行に関する情報などを含む完全なテーブルをコピーする場合、インデックスもコピーできると思います。
現在のPostgreSQLの動作の場合、あるテーブルから別のレプリカテーブルにデータをコピーすると、論理的一貫性のみが保証されます。つまり、元のテーブルは新しいテーブルに存在し、データは行レベルでのみ一致する行になります。
物理的整合性に関して、元のテーブルのディスクにデータが物理的に格納される方法が、レプリカテーブルのデータ。
これが重要な理由は、インデックスがテーブル内のデータに関するいくつかの情報を[〜#〜] ctid [〜# 〜]データを含む行。
端的に言えば、創造的なハッキングを除いて、これらのインデックスを新しいテーブルで再構築する必要があるというのが常識だと思います。申し訳ありませんが、良いニュースはありません。