Upsert PostgreSQL tidak berfungsi pada Tabel Partisi

9

Punya tabel seperti ini:

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

Tabel ini adalah master dari mana banyak partisi mewarisi. Partisi dilakukan oleh MONTH di bidang DATE. Sebagai contoh: Partisi untuk Agustus-2017 akan menjadi agg_201708 dan PK-nya adalah pk_agg_201708. Ada pemicu yang biasa SEBELUM INSERT untuk mengarahkan ulang penyisipan ke partisi yang tepat.

Masalahnya adalah saya ingin melakukan UPSERT ke dalam tabel ini. Bagian DO CONFLICT tidak berfungsi.

Kode dulu seperti ini

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

Tapi kemudian saya perhatikan bahwa kendala (pk_aggregated) adalah yang ada di tabel master, dan bukan pada tabel anak di mana penyisipan akan benar-benar dilakukan, karena pemicunya.

Saya mengubah klausa CONFLICT ke:

ON CONFLICT (user, type, date)

Yang merupakan bidang PK, tetapi ini juga tidak berhasil.

Adakah yang tahu bagaimana membuat ini bekerja?

Sergi Porta
sumber
2
Jangan berpikir itu karena keterbatasan dalam implementasi. Seharusnya benar-benar mendeteksi itu dan KESALAHAN. Laporkan bug?
Craig Ringer
5
Lihat juga utas milis ini postgresql.org/message-id/…
Craig Ringer

Jawaban:

6

PostgreSQL 11 mendukung INSERT INTO ... ON CONFLICTdengan tabel dipartisi:

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;

Demo DBFiddle


Batasan ddl-partisi

5.10.2.3. Keterbatasan

Menggunakan klausa ON CONFLICT dengan tabel dipartisi akan menyebabkan kesalahan, karena batasan unik atau pengecualian hanya dapat dibuat pada partisi individu. Tidak ada dukungan untuk menegakkan keunikan (atau batasan pengecualian) di seluruh hierarki partisi.

telah diangkat.

Lad2025
sumber
11

Upsert pada tabel partisi tidak diimplementasikan dalam versi lebih awal dari Postgres 11.

Di Postgres 9.6:

Pernyataan INSERT dengan klausa ON CONFLICT tidak mungkin berfungsi seperti yang diharapkan, karena tindakan ON CONFLICT hanya diambil jika terjadi pelanggaran unik pada relasi target yang ditentukan, bukan pada hubungan anak-anaknya.

Partisi deklaratif tidak menyelesaikan masalah, Postgres 10:

Menggunakan klausa ON CONFLICT dengan tabel dipartisi akan menyebabkan kesalahan, karena batasan unik atau pengecualian hanya dapat dibuat pada partisi individu. Tidak ada dukungan untuk menegakkan keunikan (atau batasan pengecualian) di seluruh hierarki partisi.

Penanganan masalah

Di Postgres 11 Anda dapat menggunakan ON CONFLICTtabel dipartisi, lihat jawaban lad2025.

klin
sumber
Jawaban ini perlu diperbarui untuk pg11, yang mengimplementasikannya, seperti catatan @ lad2025.
DB140141
@ DB140141 - thx, jawabannya diperbarui.
klin