Wir führen ungefähr 100.000 DDL-Anweisungen in einer einzelnen Transaktion in PostgreSQL aus. Während der Ausführung erhöht sich die Speicherauslastung der jeweiligen Postgres-Verbindung allmählich. Sobald kein Speicher mehr verfügbar ist (von 10 MB auf 2,2 GB bei 3 GB RAM), trifft OOM Killer sie mit 9, was dazu führt, dass Postgres in den Wiederherstellungsmodus wechselt .
BEGIN;
CREATE SCHEMA schema_1;
-- create table stmts - 714
-- alter table add pkey stmts - 714
-- alter table add constraint fkey stmts - 34
-- alter table add unique constraint stmts - 2
-- alter table alter column set default stmts - 9161
-- alter table alter column set not null stmts - 2405
-- alter table add check constraint stmts - 4
-- create unique index stmts - 224
-- create index stmts - 213
CREATE SCHEMA schema_2;
-- same ddl statements as schema_1 upto schema_7
-- ...
-- ...
-- ...
CREATE SCHEMA schema_7;
COMMIT
Einschließlich der Anweisung zum Erstellen eines Schemas sollten ungefähr 94304 DDL-Anweisungen ausgeführt werden.
Gemäß Transactional DDL in PostgreSQL
Wie bei mehreren kommerziellen Wettbewerbern ist eine der fortschrittlicheren Funktionen von PostgreSQL die Fähigkeit, Transaktions-DDL über das Write-Ahead-Protokolldesign durchzuführen. Dieses Design unterstützt das Zurücksetzen auch großer Änderungen an DDL, z. B. der Tabellenerstellung. Sie können nicht von einem Hinzufügen / Löschen in einer Datenbank oder einem Tabellenbereich wiederherstellen, aber alle anderen Katalogvorgänge sind umkehrbar.
Wir haben sogar problemlos ungefähr 35 GB Daten in einer einzigen Transaktion in PostgreSQL importiert. Warum benötigt die Postgres-Verbindung jedoch großen Speicher, wenn Tausende von DDL-Anweisungen in einer einzigen Transaktion ausgeführt werden?
Wir können das Problem vorübergehend beheben, indem wir den Arbeitsspeicher erhöhen oder den Swap zuweisen. Wir können jedoch sagen, dass die Anzahl der Schemaerstellungen in einer einzelnen Transaktion auf 50 bis 60 (ca. 1 Million DDL-Anweisungen) ansteigen kann, was mehr als 100 GB RAM oder Swap erfordern würde was momentan nicht machbar ist.
PostgreSQL-Version: 9.6.10
Gibt es einen Grund, warum das Ausführen vieler DDL-Anweisungen mehr Speicher erfordert, während dml-Anweisungen dies nicht tun? Behandeln nicht beide Transaktionen, indem sie in die zugrunde liegende WAL schreiben? Warum ist es für DLL anders?
Grund für eine einzelne Transaktion
Wir synchronisieren die gesamte Kundendatenbank von Customer Premise (SQL Server) mit Cloud (PostgreSQL). Alle Kunden haben unterschiedliche Datenbanken. Der Prozess ist, dass ganze Daten als CSV von SQL Server generiert und mithilfe von Temp Tables, COPY und ON CONFLICT DO UPDATE in PostgreSQL importiert werden. Während dieses Prozesses behandeln wir jeden Kunden als eine einzelne Datenbank in PG und eine einzelne Datenbank im SQL Server des Kunden als Schemas in der PG-Datenbank des Kunden.
Basierend auf den CSV-Daten werden wir die Schemas dynamisch erstellen und Daten in sie importieren. Gemäß unserem Anwendungsdesign sollten die Daten in PG zu jedem Zeitpunkt streng konsistent sein und es sollten keine Teilschemata / Tabellen / Daten vorhanden sein. Das mussten wir also in einer einzigen Transaktion erreichen. Außerdem synchronisieren wir alle 3 Minuten schrittweise vom Kunden zur Cloud-Datenbank. Die Schemaerstellung kann also entweder in der ersten oder inkrementellen Synchronisierung erfolgen. Die Wahrscheinlichkeit, so viele Schemas in der ersten Synchronisierung selbst zu erstellen, ist jedoch sehr hoch.
Update 1
Durch das Kommentieren der ALTER TABLE ALTER COLUMN
Anweisungen wurde die Speichernutzung erheblich reduziert, da jetzt nur noch maximal 300 MB benötigt werden. Müssen diese in den CREATE TABLE
Aussagen selbst zusammenführen.
Wird das Kernproblem in der Mailingliste von PG Hackers fragen.
quelle
CREATE DATABASE
sie nicht innerhalb eines Transaktionsblocks ausgeführt werden kann ) oder wird sie in einem separaten Prozess ausgeführt? Verwandte Frage (möglicherweise eine Umformulierung der vorherigen): Wie wird die Anwendung auf einen neuen Kunden / eine neue Datenbank aufmerksam?Antworten:
Eine bessere Idee ist es, SQL Server FDW zu verwenden, das tatsächlich die Logik hat, Microsoft SQL Server in das PostgreSQL-Format zu ziehen (wird beispielsweise
Bit
zugeordnetBool
). Von diesem PunktDann alle drei Minuten
last_fetch_schema
last_fetch_schema
anders ist alslocal_schema
INSERT INTO ... SELECT ON CONFLICT DO UPDATE
und können nur die neuesten Daten auswählen.last_fetch_schema
Was gewinnen Sie?
CREATE TABLE local.foo ( LIKE foreign.foo)
quelle
Dieser Kommentar in src / backend / utils / cache / relcache.c scheint relevant zu sein:
Ich verstehe es nicht wirklich, denn wer ist dieser "Jemand", der einen Zeiger haben könnte? Dies ist privater Speicher, kein gemeinsam genutzter Speicher. Wie auch immer, es scheint das Aufblähen zu erklären, da jede 'alter table'-Anweisung in derselben Transaktion eine weitere Kopie von TupDesc für diese Tabelle hinterlässt. Und anscheinend
alter table
hinterlässt jede einzelne Aktion eine Kopie , selbst wenn Sie mehrere Aktionen in einer verwenden . Was auch immer die Vorzüge sein mögen, dies erklärt einen großen Teil der Speichernutzung.Weitere Informationen finden Sie in der Mailliste der pg-Hacker .
quelle