web-dev-qa-db-ja.com

Greenplum:一意の制約違反に重複しない行を挿入する

次のようなストアドプロシージャがあります。

INSERT INTO schema.my_unique_values
     SELECT DISTINCT id, value
       FROM schema.a_huge_table
      WHERE NOT EXISTS (SELECT 1
                          FROM schema.my_unique_values)

要約すると、このクエリは、a_huge_tableからmy_unique_valuesテーブルに一意の行を挿入します。

私が抱えている問題は、理由のためにマルチスレッドスクリプトでこのクエリを同時に実行すると、重複する行が挿入される可能性があることです。この「ファントム読み取り」を回避するためにシリアライズ可能を使用しようとしましたが、それでもうまくいきません。私の考えは、Postgresが一意の制約違反に対して重複しない行のみを挿入できるようにすることです。しかし、これは可能ですか?私の現在の経験では、一意の制約違反が発生すると、トランザクション全体がキャンセルされるため、重複しない行は挿入されません。どうすれば目標を達成できますか?

注:Postgres8.2を使用しているGreenplum4.3.11を使用しているため、使用できるクエリには制限があります。

ありがとう..

1
kelvien

まず、クエリを少し変更する必要があると思います。これは、現在記述されているWHERE NOT EXISTSは、テーブルに行があるとすぐにfalseになるためです。 WHERE句を指定する必要があります。

_INSERT INTO schema.my_unique_values
     SELECT DISTINCT id, value
       FROM schema.a_huge_table a
      WHERE NOT EXISTS 
             (SELECT 1
                FROM schema.my_unique_values m
               WHERE m.id = a.id AND m.value = a.value)
_

INSERTは、トランザクション内で、または単一ステートメントトランザクションとして、アトミックになります。したがって、1つの行が失敗すると、すべてが失敗します。いずれにせよ、あなたはできませんSERIALIZABLEトランザクション分離レベル。その分離レベルに達していない場合は、NOT EXISTS (...)に正しく記述されたWHERE句があることを確認してください。

PostgreSQLバージョン9.5の時点で、INSERTの一部となることができ、ユースケースを正確に検索する新しい句があります。 _ON CONFLICT DO NOTHING_ を利用するようにクエリを変更できます。

_INSERT INTO schema.my_unique_values
     SELECT DISTINCT id, value
       FROM schema.a_huge_table a
ON CONFLICT DO NOTHING ;
_

注:_ON CONFLICT_句は、INSERT全体ではなく、各行に適用されます。

1
joanolo

別のアイデアとして、これはキャッシュテーブルです。私はそれらのファンではありません。 (id,value)schema.a_huge_tableから削除されるとどうなりますか?

CREATE MATERIALIZED VIEW schema.my_unique_values AS
  SELECT DISTINCT id, value
  FROM schema.a_huge_table;

それからあなたがそれをリフレッシュしたいとき..

REFRESH MATERIALIZED VIEW schema.my_unique_values

更新することもできますCONCURRENTLY

REFRESH MATERIALIZED VIEW CONCURRENTLY schema.my_unique_values

マテリアライズド・ビューの同時選択をロックアウトせずに、マテリアライズド・ビューをリフレッシュします。このオプションがないと、多くの行に影響を与える更新は、使用するリソースが少なくなり、より迅速に完了する傾向がありますが、マテリアライズド・ビューから読み取ろうとしている他の接続をブロックする可能性があります。影響を受ける行数が少ない場合は、このオプションの方が高速になる可能性があります。

言うまでもなく、それは常に完璧なソリューションです。しかし、私は一般的に、それが合理的な範囲のほとんどのものにとってより良い解決策であると思います。

0
Evan Carroll