Schlacht von MERGE. Chronik mit Schlussfolgerungen und Moral

Einige Wochen vor dem wichtigen Commit-Festival - dem letzten vor der feature freeze Version von PostgreSQL 11 - sahen sich die Hacker- Newsletter, die den Chipsatz im linken Paket komprimierten, den MERGE- Thriller an. Der Thriller-Regisseur und CEO von 2ndQuadrant, Simon Riggs , versuchte mit beeindruckender Ausdauer und Einfallsreichtum, einen Patch zu veröffentlichen, der die Syntax des MERGE-Befehls in die Version implementiert. Riggs ist seit 2009 ein Comedian und mit dem Status eines Comedians können Sie Patches selbst genehmigen. Er wurde von nicht weniger angesehenen PostgreSQL-Komitees und Veteranen abgelehnt. Die Leidenschaften brodelten klar und implizit, es kam nicht einmal zu direkten Beleidigungen - eine überraschende Tatsache für Stammgäste in vielen Inlandsforen. Bis zur Klärung der Frage blieb jedoch eine gewisse Spannung bestehen, und es gibt nichts zu streiten.

Aber Leidenschaften sind Leidenschaften (sie werden weiter besprochen), und ich möchte die Essenz dieses völlig weit hergeholten Problems leidenschaftslos herausarbeiten.


Draußen verschmelzen


Wenn es vollständig vereinfacht ist, ist die Sache folgende: Wir haben 2 Tabellen mit denselben Feldern und unterschiedlichen Daten. Nehmen Sie Namen und Alter an. Wir müssen sie zu einem kombinieren. Es wäre jedoch notwendig zu entscheiden, was mit den Persönlichkeiten in beiden Tabellen geschehen soll. Höchstwahrscheinlich wollen wir alles in der Final Table und aktualisieren die Informationen auf übereinstimmende Personen. Es ist klar, dass dies auch in dieser Umgebung eine sehr häufige Aufgabe ist. Es kann ohne MERGE gelöst werden, eine komplexe Anfrage stellen, Sie können Trigger verwenden und so weiter. Aber es ist unpraktisch. Die nicht-kanonische Version von MERGE, die UPSERT (UPdate + inSERT) heißt, löst dieses Problem jedoch.

Der MERGE-Operator befindet sich im SQL-2003-Standard und ist in SQL-2008 bereits in seiner ganzen Pracht. Es ist in Oracle, DB2 und in MS SQL implementiert, was bedeutet, dass das Fehlen von MERGE diejenigen verärgert, die erwägen, von diesen DBMS auf PostgreSQL umzusteigen. Simon Riggs 'sehnsüchtiger Wunsch, so schnell wie möglich, bereits in PostgreSQL 11, wurde von den Wünschen der Kunden von 2ndQuadrant angetrieben und nicht von Ehrgeiz oder Streit.

Tatsächlich verfügt MERGE über umfangreiche Funktionen. Die Daten müssen nicht aus Tabellen entnommen werden, insbesondere nicht aus ähnlichen Strukturen.

Die Befehlssyntax lautet wie folgt:

  MERGE INTO tablename USING table_reference ON (condition) WHEN MATCHED THEN UPDATE SET column1 = value1 [, column2 = value2 ...] WHEN NOT MATCHED THEN INSERT (column1 [, column2 ...]) VALUES (value1 [, value2 ...]); 

Sie können jedoch Folgendes tun:

 MERGE [hint] INTO [schema .] {table | view} [table_alias] USING { subquery | [schema .] { table | view}} [table_alias] ON ( condition ) [ merge_update_clause ] [ merge_insert_clause ] [ error_logging_clause ] ; 

Diese Syntax ist in Oracle implementiert. Mit anderen Worten, dann führt MERGE Aktionen aus, mit denen die Datensätze in der Zieltabelle target_table_name mithilfe von data_source in einem einzelnen SQL-Befehl geändert werden. Je nach den Bedingungen kann INSERT, UPDATE oder DELETE in Bezug auf die Datensätze in target_table_name ausgeführt werden. In diesem Fall kann target_table_name eine Ansicht sein, und data_source kann eine Reihe von Tabellen oder Ansichten sein, die das Ergebnis einer Unterabfrage sind .

Zunächst führt die MERGE einen left outer join für die data_source mit dem target_table_name , wobei 0 oder mehr Kandidatenänderungsdatensätze vorgeschlagen werden. WHEN Klauseln werden in der angegebenen Reihenfolge berechnet. Sobald die Bedingung erfüllt ist, wird die entsprechende Aktion ausgeführt. Schlüsselwörter WHEN [NOT] MATCH THEN sind in SQL nicht sehr verbreitet, daher erinnern wir Sie daran, dass dies ein Steuerelementkonstrukt wie if-else in anderen Sprachen ist. MERGE target_table_name DELETE in Bezug auf target_table_name genauso wie UPDATE, INSERT oder DELETE , nur die Syntax des gesamten Befehls ist unterschiedlich.

Eine Klausel mit ON muss eine Verbindung zu allen Spalten des Primärschlüssels herstellen. Wenn andere Spalten angegeben werden, muss ein eindeutiger Index verwendet werden, damit die [NOT] MATCHED sofort die Aktionen für den Kandidatendatensatz bestimmen, um die Interaktion mit anderen Transaktionen auszuschließen.

MERGE deterministischer Befehl: Sie können denselben Datensatz nicht mehrmals im selben MERGE-Befehl aktualisieren.
Ein Beispiel:

 MERGE CustomerAccount CA USING RecentTransactions T ON T.CustomerId = CA.CustomerId WHEN MATCHED THEN UPDATE SET Balance = Balance + TransactionValue WHEN NOT MATCHED THEN INSERT (CustomerId, Balance) VALUES (T.CustomerId, T.TransactionValue); 

oder mit einer Unterabfrage:

 MERGE INTO bonuses D USING (SELECT employee_id, salary, department_id FROM employees WHERE department_id = 80) S ON (D.employee_id = S.employee_id) WHEN MATCHED THEN UPDATE SET D.bonus = D.bonus + S.salary*.01 DELETE WHERE (S.salary > 8000) WHEN NOT MATCHED THEN INSERT (D.employee_id, D.bonus) VALUES (S.employee_id, S.salary*.01) WHERE (S.salary <= 8000); 

In IBM DB2 funktioniert auch die Syntax. Wie sie sagen , "unter der Haube" wird dies ähnlich wie beim UPDATE FROM Konstrukt gemacht.
Seit 2008 hat MS SQL auch MERGE .

Aber selbst hinter einer einzigen Standardsyntax beginnt das Problem der Auswahl aus einer beträchtlichen Anzahl von Mechanismen und Implementierungsmethoden. Das Team sollte auf verschiedenen Ebenen der Transaktionsisolation mit unterschiedlichen Sperralgorithmen arbeiten und sich auf wettbewerbsintensive oder weniger wettbewerbsfähige Betriebsarten konzentrieren. Und um diese komplizierte Logik zu implementieren, müssen Sie, wie Sie vielleicht vermuten, viele DBMS-Komponenten berühren.

UPSERT, Pseudo-MERGE


Es ist klar, dass DBMS-Entwickler nach Kompromisslösungen suchten und sich weigerten, die Standardsyntax buchstäblich zu reproduzieren. Das Plus dieses Ansatzes ist die Freiheit. Sie können organische Mechanismen verwenden, die für ein bestimmtes DBMS organisch sind. Sie können die Implementierung für Aufgaben optimieren, die Sie für Ihre Benutzer als am relevantesten erachten.

In MySQL gibt es beispielsweise einen REPLACE Befehl, der wie INSERT funktioniert. Wenn jedoch die neuen und alten Zeilen im PRIMARY KEY oder UNIQUE Index dieselben Werte haben, wird die alte Zeile vor dem Einfügen der neuen Zeile gelöscht. Es gibt aber auch INSERT ... ON DUPLICATE KEY UPDATE wo INSERT und UPDATE auftreten (anstelle von DELETE in REPLACE ). Das ist UPSERT . Und es gibt INSERT IGNORE , das das Einfügen einfach nicht durchführt, ohne unter bestimmten Einschränkungen einen Fehler (aber eine Warnung) in der INSERT IGNORE .

Chroniken von PG MERGE


In der PostgreSQL-Community begann das Gespräch über MERGE im Jahr 2005, als Jaime Casanova fragte, ob jemand in der Community mit der Entwicklung von MERGE . Peter Eisentraut schlug vor, zu diskutieren, ob es sich lohnen würde, eine MERGE-Option für PostgreSQL zu entwickeln: eine ähnliche Implementierung in MySQL, oder es wäre besser, Ihre Bemühungen auf eine Oracle-Version des MERGE Typs zu lenken, die eine MERGE Funktionalität aufweist. Lohnt es sich jedoch, Anstrengungen in diese Richtung zu unternehmen?

Inmitten einer kurzen Diskussion erscheint der Protagonist dieser Erzählung Simon Riggs mit den Worten:
MERGE ist sowohl für OLTP-Systeme als auch für DW (Data Warehouse - Data Warehouses, dh analytische Anwendungen, bei denen komplexe Abfragen, aber nicht zu wettbewerbsfähige Umgebungen und Daten selten aktualisiert werden und wenn sie aktualisiert werden, normalerweise in großen Blöcken, nützlich. <...> Wir können MERGE als eine Variante von COPY FROM implementieren, es wird sehr cool sein.

Alle sind sich einig: Ja, cool. Genauer gesagt, fast alles: Stephen Frost : Ich glaube, ich bin nicht der einzige, der sagt, dass ich einen vollwertigen, konformen MERGE-Standard brauche.

Bruce Momjian hat einen anderen, pragmatischeren Vorschlag: Es scheint mir, dass wir einige Optionen, die wir implementieren können, in MERGE implementieren müssen, und im Rest werden wir einen Fehler geben (und in Fällen, in denen es notwendig sein wird, die gesamte Tabelle zu blockieren). Und nachdem wir Feedback von Benutzern erhalten haben, werden wir überlegen, was als nächstes zu tun ist.

Aber bisher passiert nichts.

Das Eis ist gebrochen


Im Jahr 2008 forderte Simon Riggs erneut auf, sich mit MERGE zu befassen - welche der Möglichkeiten zu wählen (zu diesem Zeitpunkt erschien bereits eine neue Version von MERGE im SQL-2008-Standard, soweit es sich um einen Entwurf handelte). Er malt ausführlich die aktuelle Implementierung von Oracle, IBM und MS SQL sowie die alternative Syntax von MySQL und Teradata. Und wenig später erwähnt er bereits den Beginn der Arbeit im 2. Quadranten in dieser Richtung.

Peter Eisentraut schreibt in seinem Blog : Natürlich ist Riggs einer der qualifiziertesten Spezialisten, er kann die Arbeit an der Implementierung von MERGE leiten.

Aber hier kommt die erste unerwartete Wendung: Ein Student ist in das Problem involviert - ein Teilnehmer an der Entwicklung des GSoC- Programms, dh Google Summer of Code. Sein Name ist Boxuan Bxzhai - ich nehme nicht an, den Nachnamen zu transkribieren. Bald schreibt er, dass die Arbeit fast erledigt ist.

Aber fast zählt nicht. Greg Smith von 2ndQuadrant (d. H. Simon Riggs Verbündeter) schreibt:
Wir haben also einen Patch im Code, der ein halbes Dutzend schwerwiegender ungelöster Probleme enthält. Ich schweige über die Kleinen. Die Probleme sind zu tief, um den Code für das Commitfest fertigzustellen. Inzwischen ist seit langem nichts mehr von Boxuan zu hören. Wir könnten ihm helfen, aber wo ist er? Wer weiß Bescheid?

Eine Diskussion über Implementierungspfade wird 2014 wieder aufgeflammt, aber es passiert wieder nichts: Es gibt keinen Code.

Schließlich schreibt Simon Riggs bereits 2017 :
Ich arbeite an Code, um MERGE für PostgreSQL Version 11 zu übernehmen . Wir verwenden dieselben Mechanismen, die dem bereits funktionierenden INSERT ON CONFLICT zugrunde INSERT ON CONFLICT , sodass keine Änderungen an der Infrastruktur erforderlich sind. Grundsätzlich wird nur die Syntax zusätzlich zu den verfügbaren implementiert. Aber ich schreibe meinen Code von Grund auf neu, ich verwende keine früheren Entwicklungen.

Wir sprechen über Peter Geoghegan ( VMware ), der zu diesem Zeitpunkt bereits in 9.5 alternativer INSERT .. ON CONFLICT UPDATE Syntax INSERT .. ON CONFLICT UPDATE , anders als der SQL-Standard, aber immer noch mit MERGE und REPLACE in MySQL verbunden.

Zuerst wurde Simons Arbeit mit Ausrufen von Nizza Arbeit getroffen! Obwohl Robert Haas unterstützend ist, warnt er vor möglichen Serialisierungsanomalien. INSERT .. ON CONFLICT UPDATE mit INSERT .. ON CONFLICT UPDATE umzugehen INSERT .. ON CONFLICT UPDATE , ohne MERGE an der Basis, ist es irgendwie ruhiger.

PostgreSQL UPSERT Autor UPSERT selbst:
Ich würde den MERGE ON CONFLICT DO UPDATE und MERGE nicht mischen. <...> Zum Laden großer Datenmengen ( bulk load ) würde ich beispielsweise den merge join Algorithmus verwenden. <...> Im Allgemeinen MERGE die Vorteile von MERGE damit zusammen, dass normale Verbindungen dort auf die übliche Weise funktionieren: nested loop, hash, merge . Und in INSERT … ON CONFLICT gibt es überhaupt keine Joins.

Haas: Wie Peter denke ich, dass auf diese Weise eine so starke Sperre bei der Ausführung einer DML Anfrage DML aussieht. Es ist unwahrscheinlich, dass sich jemand darüber freut, dass nur eine Person gleichzeitig mit MERGE arbeiten kann.

Für Neugierige: Geigan zerlegt hier und hier die Feinheiten und UPSERT Unterschiede zwischen MERGE und MERGE (wir speichern die archivierte Korrespondenz von PostgreSQL auf unserer Website).

Simon widersetzt sich. Er appelliert an die jüngste Geschichte. Zum Thema Abschnitt sagten sie auch "eine neue Syntax, nichts weiter". Aber es stellte sich als sehr nützliche Sache heraus. Aber ich habe nicht vor, sofort alles zu realisieren, was in MERGE ist. Wir werden das Gleiche tun wie bei der Partitionierung - wir teilen die Entwicklung in Phasen ein.

Und noch ein Argument ist meiner Meinung nach sehr überzeugend: Gut. Aber lass uns wählen. Ich schlage eine praktische Option vor. 10 Jahre werden bald vom ersten ernsthaften Versuch kommen, MERGE zu entwickeln. Ist es nicht an der Zeit, etwas zu tun, um eine nützliche Lösung zu finden, anstatt auf weitere 10 Jahre der perfekten Lösung zu warten? Vorausgesetzt, es existiert überhaupt.

Schließlich kommt der Patch in der Community an. Welches Datum? Stellen Sie sich bitte vor. Nein, sie haben es nicht erraten: Simon schickt ihn am 30. Dezember 2017. Und legt fest, dass dies ein WIP-Patch ist, dh Work in Progress - ein Patch in Arbeit.

Simon, Januar:
Der Patch wird ohne spezielle Fehler abgeschlossen. 1200 Codezeilen plus Tests und Dokumentation. Ich werde ihn für dieses Commitfest verpflichten, und wir werden die RLS- (Row Level Security - Schutz auf Aufzeichnungsebene) und Partitionierungsunterstützung später abschließen.

Kaste der Ausschüsse


Hier müssen wir einen Schritt beiseite treten und die Rolle des Kommissars in der Gemeinde erklären. Die Funktionen des Beauftragten, dh desjenigen, der befugt ist, den Patch in der nächsten Version zu akzeptieren, haben sich historisch geändert. Es war einmal, als es nur wenige Entwickler gab, das Recht, sich zu verpflichten, wurde großzügig verteilt. Zum Beispiel erhielt der berühmte (auf einem ganz anderen Gebiet) Julian Assange den Titel eines Kommandanten, der nur sechs Patches verfasste. Jetzt ist es nicht einfach, Kommissar zu werden. Auf der Liste von ein paar Dutzend Personen stehen keine Emporkömmlinge. Boyus Momdjan ( EnterpriseDB ) hat 13.363 Commits, Tom Lane (Tom Lane, Crunchy Data ) 13127, Robert Haas ( EnterpriseDB ) - 2074. Der einzige Committer aus Russland ist übrigens Fedor Sigaev (Teodor Sigaev, Postgres Professional ) mit seinen 383 Commits . Simon Riggs selbst hat 449 von ihnen. Ich wiederhole: Er hat als Kommissar genug Autorität, um Patches zu nehmen und zu begehen - seine und seine Mitarbeiter. Eine andere Sache ist, dass es sich kaum lohnt, dies zu tun, indem man offen die Meinungen anderer führender Leuchtenkomitees vernachlässigt. Sie können auch den Status eines Kommissars entziehen, aber zumindest werden sie revert Patch zurücksetzen.

Bruch im Kampf


Natürlich finden sie in dem "hoffnungslosen" Patch, der im Allgemeinen hastig erstellt wurde, neue Fehler. Neue Versionen rollen als Antwort.

Ende Januar erscheint ein neuer Charakter: der Entwickler von 2ndQuadrant Pavan (sein Name ist jeder mit Namen; vollständig Pavan Deolasee). Jetzt hat es die Community mit einem Tandem zu tun: Pavan sendet neue Versionen und bedankt sich für die Kritik, und Simon bricht sie mit einem bemerkenswerten Marketingdruck.

Haas: Ich denke nicht, dass es sich lohnt, einseitige Entscheidungen über den Ausschluss von Funktionen zu treffen, die überall funktionieren. Wenn wir uns einig sind, dass einige Funktionen nicht in diesem Patch enthalten sind, ist dies eine Sache. Und es ist völlig anders, dass in den Kommentaren zu diesem Anlass alle ihre Uneinigkeit zum Ausdruck brachten. Und wir haben tatsächlich nicht gehört, warum diese Funktionen ausgeschlossen werden sollten.

Die Logik wurde wie folgt dargestellt:

  • a priori gibt es ernsthafte Probleme, weil sie nur in den Entwicklungen im Stil des "Kavallerieangriffs" liegen können.
  • Die Unterstützung selbst wichtiger Funktionen wie der neuen Partitionierung in den Versionen 10-11, CTE (Common Table Expressions = WITH-Abfragen) oder RLS (Row Level Security) kann auch dann abgeschlossen werden, wenn der Patch in der aktuellen Version akzeptiert wurde, jedoch nur, wenn die vorgeschlagene Architektur für den Aufbau auf der Oberseite geeignet ist ihre gewünschte Funktionalität.

Der zweite Peter Geigan formuliert dies:
Normalerweise achte ich auf die Unterstützung verschiedener Funktionen, da dies die allgemeine Überzeugung stärkt, dass das Design so gestaltet ist, wie es sollte . Und wenn solche Probleme durch die Unterstützung von WITH Ausdrücken [ CTE ] verursacht werden, komme ich auf die Idee, dass die zugrunde liegende Architektur so ist, dass sie hier und da Probleme verursacht.

In der Zwischenzeit nähert sich die Stunde X (das letzte Komiteefest) und die Wolken über MERGE ziehen auf. Es ist nicht so, dass die Gründerväter speziell ernsthafte Probleme in der Architektur der Patches von Simon und dann Pavan suchten. Ich musste nicht nach Problemen suchen, sie öffneten sich bereitwillig.

Die Auflösung nähert sich


Die Handlung beschleunigt sich. Trotz der coolen Haltung anderer Komitees zu seinem Unternehmen beschließt Simon am 2. April , den Befehl nach dem SQL: 2016- Patch zu übernehmen, fügt die Dateien hinzu, Depesz (Hubert Lubachevsky) schafft es , ihn auf seinem Blog anzukündigen , aber am selben Tag rollt Simon alles zurück, weil Fehler.

Legen Sie am nächsten Tag erneut fest, indem Sie WITH Unterstützung hinzufügen.

Als Reaktion darauf sind die Vorwürfe wirklich schwerwiegend. Andres Freund ( EnterpriseDB ) schreibt:
Die Architektur für MERGE im Parser und im Executor hat mich nicht zuverlässig beeindruckt. Das Erstellen versteckter Verknüpfungen während der Parsing-Analyse ist eine wirklich schlechte Idee. Diese Struktur des Executors muss komplett geändert werden.

Tom Lane:
Das Design des Analysebaums ist schwach.



Sie überladen die InsertStmt Funktion, fährt er fort, sie führt INSERT überhaupt nicht aus, hat aber zufällig die gleichen Felder wie das ursprüngliche. Und nicht alle, aber einige. Das ist schlecht, es führt zu Verwirrung.

Fügen wir Beobachtungen von Fedor Sigayev hinzu :
Im Parser wurden MERGE bezogene INSERT Knoten MERGE , die mit einer Reihe zusätzlicher Felder aufgehängt waren. Wenn Sie sich den Ausführungsplan in ANALIZE , werden Sie nicht sofort verstehen, ob es sich um ein reguläres INSERT oder um MERGE : MERGE zu verstehen, müssen Sie sich zusätzliche Felder ansehen.


Simon, ruhig: OK, wir werden das ändern und morgen eine neue Datei senden .
Haas: Ich stimme Peter zu. Die Wahl der Architektur ist erfolglos.

Simon gibt nicht auf. Als Reaktion auf die Kritik an Tom Lane begeht der 6. April einen neuen Patch in der im Parser geänderten Fassung.

Verhandlung und Kapitulation


Bruce Momjan 6. April :
Ich möchte darauf hinweisen, dass die Leute Sie nicht gebeten haben, hart zu arbeiten, um dringend etwas zu reparieren. Sie haben dich gebeten, den Patch zurückzuziehen. Sie können natürlich hart arbeiten und hoffen, dass sie ihre Meinung ändern, aber auch hier haben sie Sie nicht danach gefragt.

Simon: Wenn Tom [Lane] und Andres [Freund] in den verbleibenden Tagen immer noch das Gefühl haben, dass ihre Befürchtungen nicht zerstreut wurden, werde ich den Patch gerne ohne weiteres zurücksetzen.

Tom Lane: Ich stimme immer noch dafür, dass der Patch zurückgesetzt wird. Selbst wenn er jetzt perfekt wäre, haben die Menschen jetzt keine Zeit, sich davon zu überzeugen - bis hin zu anderen dringenden Angelegenheiten.

Das ist alles.

Simon sagte OK und der Kampf bei MERGE vorbei. Alle Patches wurden zurückgepumpt, das Thema wurde auf das nächste Commitfest mit dem Status "Warten auf den Abschluss des Autors" verschoben. Die Teilnehmer der Show schlossen Frieden.


Nach der Korrespondenz der letzten Wochen scheint jedoch eine gewisse Spannung bestehen zu bleiben.

Versprochene Moral


  • Glücklicherweise verfügt die PostgreSQL-Community über natürliche und formale Mechanismen für das (fast) konfliktfreie Screening von Versuchen unreifer Lösungen. Auch wenn sie von angesehenen Entwicklern im Rang eines Unternehmensleiters geschlagen werden, dessen Beitrag zur Entwicklung von PostgreSQL enorm ist. Und Kunden, denen es an Funktionalität mangelt, drängen auf Investitionen.
  • Leider bleibt die Community oft stehen. Es ist träge bei der Annahme selbst eindeutig relevanter Entwicklungen. Manchmal ist irrationaler Perfektionismus enthalten. Die Erfahrung von Postgres Professional, wo ich arbeite, bestätigt dies. Wir haben 3 Jahre lang einen großen und wichtigen Patch mit INCLUDE-Indizes erstellt . Eine nützliche Reihe von Patches für die Arbeit mit JSON / JSONB wartet noch. Der Ausdruck "Gib der Gemeinde deine Entwicklung" bedeutet nicht wirklich Geben, sondern Schlagen : Der Gast wird mit offenen Armen begrüßt und in die Quarantäne geführt.

PS: Haftungsausschluss des Autors : Wir wollten nur ein Stück Gemeinschaftsleben zeigen. Alle Namensübereinstimmungen sind zufällig :)
PPS: Samurai Natalia Levshina .

Source: https://habr.com/ru/post/de412605/


All Articles