PostgreSQL Upsertがパーティションテーブルで機能しない


9

次のようなテーブルがあります。

CREATE TABLE aggregated_master (
  "user"       BIGINT,
  type         TEXT,
  date         TIMESTAMP,
  operations   BIGINT,
  amount       NUMERIC,
  PRIMARY KEY ( "user", type, date )
);

このテーブルは、多くのパーティションが継承するマスターです。パーティションは、DATEフィールドのMONTHによって行われます。たとえば、Aug-2017のパーティションはagg_201708で、そのPKはpk_agg_201708になります。挿入を適切なパーティションにリダイレクトする通常のトリガーBEFORE INSERTがあります。

事は私がこのテーブルにUPSERTをしたいということです。DO CONFLICT部分が機能していません。

最初のコードはこのようなものでした

INSERT INTO aggregated_master (user, type, date, oeprations, amount)
SELECT user, type, date, SUM(ops), SUM(amt)
FROM ...
WHERE ...
GROUP BY USER, TYPE, DATE
ON CONFLICT ON CONSTRAINT pk_aggregated
DO UPDATE SET operations = EXCLUDED.operations
          ,   amount = EXCLUDED.amount

しかしその後、制約(pk_aggregated)がマスターテーブルの制約であり、トリガーが原因で実際​​に挿入が実行される子テーブルの制約ではないことに気付きました。

CONFLICT句を次のように変更しました。

ON CONFLICT (user, type, date)

これはPKのフィールドですが、これも機能しません。

これを機能させる方法はありますか?


2
実装上の制限によるものだとは思わないでください。それは本当にそれとエラーを検出するはずです。バグを報告?
クレイグリンガー

5
このメーリングリストのスレッドpostgresql.org/message-id/…
Craig Ringer

回答:


6

PostgreSQL 11はINSERT INTO ... ON CONFLICT分割テーブルでサポートします:

CREATE TABLE o(id INT PRIMARY KEY, i INT) PARTITION BY RANGE (id);

CREATE TABLE o1 PARTITION OF o FOR VALUES FROM (1) TO (1000);
CREATE TABLE o2 PARTITION OF o FOR VALUES FROM (1000) TO (2000);

INSERT INTO o(id, i) VALUES (1,1),(2,2),(1500,1500);

INSERT INTO o(id, i)
VALUES (1500, 1400), (2,20), (3, 3)
ON CONFLICT (id)
DO UPDATE SET i = EXCLUDED.i;

SELECT * FROM o;

DBFiddleデモ


制限ddlパーティション

5.10.2.3。制限事項

パーティション化されたテーブルでON CONFLICT句を使用すると、エラーが発生します。一意制約または除外制約は、個々のパーティションでのみ作成できるためです。パーティション階層全体で一意性(または除外制約)を適用することはサポートされていません。

解除されました。


11

Postgres 11より前のバージョンでは、パーティションテーブルのアップサートは実装されていません。

Postgres 9.6では:

ON CONFLICT句を含むINSERTステートメントは期待どおりに機能しない可能性があります。ONCONFLICTアクションは、指定されたターゲットリレーションで一意の違反が発生した場合にのみ実行され、その子リレーションでは発生しないためです。

宣言的なパーティション分割では問題は解決しません、Postgres 10:

パーティション化されたテーブルでON CONFLICT句を使用すると、エラーが発生します。一意制約または除外制約は、個々のパーティションでのみ作成できるためです。パーティション階層全体で一意性(または除外制約)を適用することはサポートされていません。

回避策

  • ("user", type, date)すべての子テーブルに一意のインデックスを作成し、
  • 例42.2に基づいて挿入/更新用の関数を作成して使用しますドキュメントで説明されているUPDATE / INSERTの例外

Postgres 11ではON CONFLICT、パーティションテーブルで使用できます。lad2025の回答を参照してください


この回答は、それを実装するpg11用に更新する必要があります(@ lad2025が注記)。
DB140141

@ DB140141-thx、回答が更新されました。
klin
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.