DBAtlas · Atlas für Datenbankbetrieb

Falle Default-Partition: neue Partition scheitert mit 'would be violated by some row'

PostgreSQLPartitionierung

Befehl

-- Which periods have rows in the default partition?
SELECT date_trunc('month', created_at)::date AS month, count(*) AS row_count
FROM sales_default
GROUP BY 1
ORDER BY 1;

-- Move the rows into a new partition and attach it in one transaction
BEGIN;
SET LOCAL lock_timeout = '5s';
LOCK TABLE sales_default IN ACCESS EXCLUSIVE MODE;
CREATE TABLE sales_2027_02 (LIKE sales INCLUDING DEFAULTS INCLUDING CONSTRAINTS);
WITH moved AS (
  DELETE FROM sales_default
  WHERE created_at >= DATE '2027-02-01' AND created_at < DATE '2027-03-01'
  RETURNING *
)
INSERT INTO sales_2027_02 SELECT * FROM moved;
ALTER TABLE sales ATTACH PARTITION sales_2027_02
  FOR VALUES FROM ('2027-02-01') TO ('2027-03-01');
COMMIT;

Was es tut

Zählt je Zeitraum die in der Default-Partition gelandeten Zeilen; verschiebt Zeilen im Bereich der neuen Partition in eine neue Tabelle und hängt diese ein, alles in einer Transaktion.

Wann einsetzen

Wenn CREATE TABLE ... PARTITION OF oder ATTACH mit 'updated partition constraint for default partition would be violated by some row' fehlschlägt oder wenn festgestellt wird, dass die Default-Partition wächst.

Vorsicht

Mit vorhandener Default-Partition scannt jede neue Partition die Default-Partition vollständig und hält währenddessen ACCESS EXCLUSIVE darauf; eine große Default-Partition bedeutet bei jeder Wartung einen Ausfall. Während Zeilen verschoben werden, ist die Default-Partition für Schreibvorgänge gesperrt; bei geringem Verkehr durchführen. Dauerhafte Lösung: Partitionen vorab anlegen und die Default-Partition per Monitoring leer halten (Alarm bei Zeilenzahl > 0) oder gar keine verwenden, damit INSERTs außerhalb des Bereichs fehlschlagen und das Problem früh sichtbar wird. Eine Default-Partition verhindert außerdem DETACH ... CONCURRENTLY.

In DBAtlas öffnen →

Verwandte Einträge