免責事項:この質問はスタックオーバーフローの質問 ここ に似ていますが、これらの答えはどれも私の問題には機能しません。後で説明します。
多くの列にインデックスが付けられているpostgresで、大きなテーブル(〜40M行、100 +列)をコピーしようとしています。現在、私は次のSQLを使用しています。
_CREATE TABLE <tablename>_copy (LIKE <tablename> INCLUDING ALL);
INSERT INTO <tablename>_copy SELECT * FROM <tablename>;
_
この方法には2つの問題があります。
テーブルサイズにより、インデックス作成はリアルタイムの問題になります。また、ファイルにダンプしてから再取り込みすることもできません。また、コマンドラインの利点もありません。 SQLでこれを行う必要があります。
私がやりたいのは、いくつかの奇跡のコマンドで正確なコピーを直接作成するか、それが不可能な場合は、インデックスなしですべての制約付きでテーブルをコピーし、それらが「精神」の制約であることを確認することですSERIAL列の新しいカウンター)。次に、すべてのデータを_SELECT *
_でコピーしてから、すべてのインデックスをコピーします。
ソース
データベースコピーに関するスタックオーバーフローの質問 :これは、3つの理由で私が求めているものではありません
pg_dump -t x2 | sed 's/x2/x3/g' | psql
_を使用し、この設定ではコマンドラインにアクセスできませんdefault nextval('x1_id_seq'::regclass)
による証拠としてシリアル列を正しく更新しませんpostgresテーブルのシーケンス値をリセットする方法 :これは素晴らしいですが、残念ながら非常に手作業です。
残念ながら、このような作業を手動で行う必要があります。しかし、それはすべてpsqlのようなものから行うことができます。最初のコマンドは非常に簡単です:
select * into newtable from oldtable
これにより、インデックスではなくoldtableのデータでnewtableが作成されます。次に、独自にインデックスやシーケンスなどを作成する必要があります。次のコマンドを使用して、テーブルのすべてのインデックスのリストを取得できます。
select indexdef from pg_indexes where tablename='oldtable';
次に、psql -Eを実行してdbにアクセスし、\ dを使用して古いテーブルを調べます。次に、これらの2つのクエリをマングルして、シーケンスに関する情報を取得できます。
SELECT c.oid,
n.nspname,
c.relname
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname ~ '^(oldtable)$'
AND pg_catalog.pg_table_is_visible(c.oid)
ORDER BY 2, 3;
SELECT a.attname,
pg_catalog.format_type(a.atttypid, a.atttypmod),
(SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)
FROM pg_catalog.pg_attrdef d
WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),
a.attnotnull, a.attnum
FROM pg_catalog.pg_attribute a
WHERE a.attrelid = '74359' AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum;
上記の74359を、前のクエリから取得したOIDに置き換えます。
PostgreSQLの_create table as
_機能が、OPが探していた答えになる可能性があります。
https://www.postgresql.org/docs/9.5/static/sql-createtableas.html
_create table my_table_copy as
select * from my_table
_
これにより、データを含む同一のテーブルが作成されます。
_with no data
_を追加すると、データなしでスキーマがコピーされます。
_create table my_table_copy as
select * from my_table
with no data
_
これにより、すべてのデータを含むテーブルが作成されますが、インデックスやトリガーなどは含まれません。
create table my_table_copy (like my_table including all)
構文のようなテーブルの作成には、すべてのトリガー、インデックス、制約などが含まれますが、データは含まれません。
最も近い「奇跡のコマンド」は次のようなものです
pg_dump -t tablename | sed -r 's/\btablename\b/tablename_copy/' | psql -f -
特に、テーブルデータを読み込んだ後にインデックスを作成します。
ただし、シーケンスはリセットされません。自分でスクリプトを作成する必要があります。
テーブル構造とデータの両方を含むテーブルを完全にコピーするには、次のステートメントを使用します。
CREATE TABLE new_table AS
TABLE existing_table;
データなしでテーブル構造をコピーするには、次のようにCREATE TABLEステートメントにWITH NO DATA句を追加します。
CREATE TABLE new_table AS
TABLE existing_table
WITH NO DATA;
既存のテーブルから部分的なデータを含むテーブルをコピーするには、次のステートメントを使用します。
CREATE TABLE new_table AS
SELECT
*
FROM
existing_table
WHERE
condition;
警告:
ソーステーブルの名前を置き換えるためにpg_dumpとあらゆる種類の正規表現を使用するすべての回答は、本当に危険です。置換しようとしている部分文字列がデータに含まれている場合はどうなりますか?データを変更することになります!
2パスソリューションを提案します。
以下は、Rubyで書かれた例です。
Ruby -pe 'gsub(/(members?)/, "\\1_copy_20130320") unless $_ =~ /^\d+\t.*(?:t|f)$/' < members-production-20130320.sql > copy_members_table-20130320.sql
上記では、「members」テーブルを「members_copy_20130320」にコピーしようとしています。データ固有の正規表現は/^\d+\t.*(?:t|f)$/
上記のタイプのソリューションは、私にとっては有効です。買い手責任負担...
編集:
OK、正規表現を嫌う人のための擬似シェル構文の別の方法を次に示します。
psql -f mytable_copy_schema.sql mydb
pg_dump -a -t mytable mydb> mytable_data.sql
どうやらテーブルを「再構築」したいようです。テーブルを再構築するだけで、コピーしない場合は、代わりにCLUSTERを使用する必要があります。
SELECT count(*) FROM table; -- make a seq scan to make sure the table is at least
-- decently cached
CLUSTER someindex ON table;
インデックスを選択し、クエリに適したインデックスを選択してください。他のインデックスが適切でない場合は、常に主キーを使用できます。
テーブルが大きすぎてキャッシュできない場合、CLUSTERは遅くなります。