PostgreSQL Upsert non funziona sulla tabella partizionata


9

Avere un tavolo come questo:

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

Questa tabella è il master da cui ereditano molte partizioni. Le partizioni vengono eseguite da MONTH nel campo DATA. Ad esempio: la partizione per agosto 2017 sarebbe agg_201708 e PK sarebbe pk_agg_201708 Esiste il solito trigger PRIMA DI INSERIRE per reindirizzare l'inserto alla partizione corretta.

Il fatto è che voglio fare un UPSERT in questa tabella. La parte DO CONFLICT non funziona.

Il codice prima era così

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

Ma poi ho notato che il vincolo (pk_aggregated) è quello sulla tabella principale e non sulla tabella figlio in cui verrà effettivamente eseguito l'inserimento, a causa del trigger.

Ho modificato la clausola CONFLICT in:

ON CONFLICT (user, type, date)

Quali sono i campi del PK, ma neanche questo funziona.

Qualche idea su come farlo funzionare?


2
Non pensare che sarà a causa di limitazioni nell'attuazione. Dovrebbe davvero rilevare questo ed ERRORE. Segnalare un bug?
Craig Ringer,

5
Vedi anche questa discussione sulla mailing list postgresql.org/message-id/…
Craig Ringer

Risposte:


6

PostgreSQL 11 supporta le INSERT INTO ... ON CONFLICTtabelle partizionate:

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 Demo


Limitazione del partizionamento ddl

5.10.2.3. limitazioni

L'uso della clausola ON CONFLICT con le tabelle partizionate causerà un errore, poiché i vincoli univoci o di esclusione possono essere creati solo su singole partizioni. Non esiste supporto per applicare l'univocità (o un vincolo di esclusione) in un'intera gerarchia di partizionamento.

è stato revocato.


11

Upsert su tabelle partizionate non è implementato in versioni precedenti a Postgres 11.

In Postgres 9.6:

È improbabile che le istruzioni INSERT con clausole ON CONFLICT funzionino come previsto, poiché l'azione ON CONFLICT viene eseguita solo in caso di violazioni univoche sulla relazione target specificata, non sulle relazioni secondarie.

Il partizionamento dichiarativo non risolve il problema, Postgres 10:

L'uso della clausola ON CONFLICT con le tabelle partizionate causerà un errore, poiché i vincoli univoci o di esclusione possono essere creati solo su singole partizioni. Non esiste supporto per applicare l'univocità (o un vincolo di esclusione) in un'intera gerarchia di partizionamento.

Soluzione

In Postgres 11 puoi usare ON CONFLICTsu tabelle partizionate, vedi la risposta di lad2025.


Questa risposta deve essere aggiornata per pg11, che la implementa, come osserva @ lad2025.
DB140141,

@ DB140141 - grazie, la risposta è stata aggiornata.
klin,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.