{"id":74953,"date":"2020-03-22T08:42:22","date_gmt":"2020-03-22T05:42:22","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/dba-gramotno-organizovyvaem-sinhronizaczii-i-importy"},"modified":"2020-03-22T08:42:22","modified_gmt":"2020-03-22T05:42:22","slug":"dba-gramotno-organizovyvaem-sinhronizaczii-i-importy","status":"publish","type":"post","link":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/dba-gramotno-organizovyvaem-sinhronizaczii-i-importy","title":{"rendered":"DBA: wir organisieren Synchronisierungen und Importe geschickt","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Bei der komplexen Verarbeitung gro\u00dfer Datens\u00e4tze (verschiedene <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/ETL\">ETL-Prozesse<\/a><\/noindex>: Importe, Konversionen und Synchronisationen mit externen Quellen) besteht h\u00e4ufig die Notwendigkeit, <b>etwas vor\u00fcbergehend zu \"merken\" und sofort schnell zu verarbeiten,<\/b> was auch immer umfangreich ist.<\/p>\n<p>Typische Aufgaben in diesem Bereich lauten normalerweise etwa so: <i>\"Hier hat die Buchhaltung die letzten Zahlungen aus dem Kundenbank abgeholt, <noindex><a rel=\"nofollow\" href=\"https:\/\/sbis.ru\/accounting\">wir m\u00fcssen diese schnell auf die Website laden und mit den Konten verkn\u00fcpfen.\"<\/a><\/noindex> Wenn das Volumen dieses \"Irgendwas\" jedoch in Hunderten von Megabyte gemessen wird und der Dienst dabei 24\/7 mit der Datenbank arbeiten muss, entstehen viele Nebeneffekte, die Ihnen das Leben schwer machen.<\/i><\/p>\n<p>Doch wenn die Menge dieses \u201eEtwas\u201c in Hunderten von Megabyte gemessen wird und der Dienst weiterhin rund um die Uhr mit der Datenbank arbeiten muss, entstehen zahlreiche Nebenwirkungen, die Ihnen das Leben schwer machen werden.<br \/>\n<img decoding=\"async\" alt=\"DBA: wir organisieren Synchronisierungen und Importe geschickt\" src=\"\/wp-content\/uploads\/2020\/03\/f74afb2cd6f5f8de26a0932166933c95.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n1. Wohin laden?<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Lassen Sie uns zun\u00e4chst kl\u00e4ren, wohin wir die Daten hochladen k\u00f6nnen, die wir \"verarbeiten\" m\u00f6chten.<\/h2>\n<p>\n1.1. Tempor\u00e4re Tabellen (TEMPORARY TABLE)<\/p>\n<h3>Im Grunde genommen sind tempor\u00e4re Tabellen in PostgreSQL genau wie jede andere Tabelle. Aberglaube wie<\/h3>\n<p>\nIm Prinzip sind tempor\u00e4re Tabellen in PostgreSQL genau wie alle anderen Tabellen. Daher sind Aberglauben wie <i><b>Hier wird alles nur im Speicher gespeichert, und der kann schnell voll sein.<\/b><\/i>Es gibt jedoch auch einige wesentliche Unterschiede.<\/p>\n<h4>Ein eigener \"Namespace\" f\u00fcr jede Datenbankverbindung.<\/h4>\n<p>\nWenn zwei Verbindungen gleichzeitig versuchen, <code>CREATE TABLE x<\/code>, wird einer von beiden garantiert <b>einen Fehler wegen Nicht-Eindeutigkeit<\/b> der Datenbankobjekte erhalten.<\/p>\n<p>Wenn jedoch beide versuchen, <code>ERSTELLEN <b>TEMPOR\u00c4R<\/b> TABELLE x<\/code>, dann k\u00f6nnen beide das erfolgreich durchf\u00fchren, und jede Verbindung erh\u00e4lt <b>ihren eigenen Instanz<\/b> der Tabelle. Und zwischen ihnen wird es keine Gemeinsamkeiten geben.<\/p>\n<h4>\u201eSelbstzerst\u00f6rung\u201c bei der Trennung<\/h4>\n<p>\nWenn die Verbindung geschlossen wird, werden alle tempor\u00e4ren Tabellen automatisch gel\u00f6scht, daher macht es keinen Sinn, <code>DROP TABLE x<\/code> manuell auszuf\u00fchren, au\u00dfer...<\/p>\n<p>Wenn Sie \u00fcber <b>pgbouncer im Transaktionsmodus arbeiten,<\/b>denn die Datenbank denkt weiterhin, dass diese Verbindung noch aktiv ist, und in dieser existiert diese tempor\u00e4re Tabelle nach wie vor.<\/p>\n<p>Daher wird der Versuch, sie erneut aus einer anderen Verbindung zu pgbouncer zu erstellen, zu einem Fehler f\u00fchren. Aber das l\u00e4sst sich umgehen, indem man <code>TEMPOR\u00c4RE TABELLE ERSTELLEN <b>WENN NICHT EXISTIERT<\/b> x<\/code>.<\/p>\n<p>Es ist jedoch besser, dies zu vermeiden, da man sonst m\u00f6glicherweise pl\u00f6tzlich Daten vom \"vorherigen Besitzer\" entdecken k\u00f6nnte. Stattdessen ist es weitaus besser, das Handbuch zu lesen und zu erkennen, dass es beim Erstellen einer Tabelle die M\u00f6glichkeit gibt, diese zu erg\u00e4nzen. <code>BEIMEN WIDMEN <b>L\u00d6SCHEN<\/b><\/code> \u2014 das hei\u00dft, dass die Tabelle nach Abschluss der Transaktion automatisch gel\u00f6scht wird.<\/p>\n<h4>Keine Replikation<\/h4>\n<p>\nAufgrund der Zugeh\u00f6rigkeit zu einer bestimmten Verbindung werden tempor\u00e4re Tabellen nicht repliziert. Allerdings <b>entfernt dies die Notwendigkeit einer doppelten Datenspeicherung<\/b> in Heap + WAL, weshalb INSERT\/UPDATE\/DELETE deutlich schneller ist.<\/p>\n<p>Aber da eine tempor\u00e4re Tabelle ja dennoch \"fast wie eine normale\" Tabelle ist, kann sie auch nicht auf der Replik erstellt werden. Zumindest bislang nicht, obwohl der entsprechende Patch schon lange bekannt ist.<\/p>\n<h3>1.2. Nicht protokollierte Tabellen (UNLOGGED TABLE)<\/h3>\n<p>\nAber was tun, wenn Sie beispielsweise einen umfangreichen ETL-Prozess haben, der nicht innerhalb einer einzigen Transaktion realisiert werden kann, und Sie dennoch <b>pgbouncer im Transaktionsmodus arbeiten,<\/b>?..<\/p>\n<p>Oder wenn der Datenstrom so gro\u00df ist, dass <b>die Bandbreite einer Verbindung<\/b> mit der Datenbank nicht ausreicht (lesen Sie: ein Prozess pro CPU)?<\/p>\n<p>Oder wenn Teile der Operationen <b>asynchron<\/b> in verschiedenen Verbindungen ablaufen?<\/p>\n<p>In diesem Fall gibt es nur eine M\u00f6glichkeit \u2014 <b>tempor\u00e4re nicht-tempor\u00e4re Tabellen erstellen<\/b>. Wortspiel, oder? Das bedeutet:<\/p>\n<ul>\n<li>hat seine eigenen Tabellen mit maximal zuf\u00e4lligen Namen erstellt, um keine \u00dcberschneidungen zu haben<\/li>\n<li><b>Extrahieren<\/b>: habe Daten aus einer externen Quelle hochgeladen<\/li>\n<li><b>Transformieren<\/b>: habe die Schl\u00fcsselverkn\u00fcpfungsfelder ausgef\u00fcllt<\/li>\n<li><b>Load<\/b>: habe die fertigen Daten in die Zieltabellen \u00fcbertragen<\/li>\n<li>habe meine eigenen Tabellen gel\u00f6scht<\/li>\n<\/ul>\n<p>\nUnd jetzt \u2014 ein Wermutstropfen. Im Grunde genommen <b>findet jede Aufzeichnung in PostgreSQL zweimal statt<\/b> \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/postgrespro\/blog\/461523\/\">zuerst im WAL<\/a><\/noindex>, dann in den Tabellen-\/Indexk\u00f6rpern. All dies geschieht zur Unterst\u00fctzung von ACID und einer korrekten Sichtbarkeit der Daten zwischen <code>BEST\u00c4TIGEN<\/code>\u2018inneren und <code>ROLLBACK<\/code>\u2018inneren Transaktionen.<\/p>\n<p>Aber das brauchen wir nicht! Der gesamte Prozess <b>ist entweder erfolgreich abgeschlossen oder nicht.<\/b>Es spielt keine Rolle, wie viele Zwischentransaktionen es gibt \u2014 uns interessiert nicht, \u201eden Prozess von der Mitte aus fortzusetzen\u201c, insbesondere wenn unklar ist, wo er war.<\/p>\n<p>Deshalb haben die Entwickler von PostgreSQL bereits in Version 9.1 eine Funktion eingef\u00fchrt, die <noindex><a rel=\"nofollow\" href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/12\/sql-createtable#SQL-CREATETABLE-UNLOGGED\">nicht protokollierte (UNLOGGED) Tabellen<\/a><\/noindex>:<\/p>\n<blockquote><p>erm\u00f6glicht. Mit dieser Angabe wird die Tabelle als nicht protokolliert erstellt. Die Daten, die in nicht protokollierte Tabellen geschrieben werden, durchlaufen nicht das Write-Ahead-Log (siehe Kapitel 29), was diese Tabellen <b>arbeiten wesentlich schneller als gew\u00f6hnliche.<\/b>. Sie sind jedoch nicht vor Ausf\u00e4llen gesch\u00fctzt; bei einem Ausfall oder einer Notabschaltung des Servers wird die unlogische Tabelle <b>automatisch gekappt.<\/b>. Au\u00dferdem wird der Inhalt der unlogischen Tabelle <b>nicht auf die nachfolgenden Server repliziert. Jegliche Indizes, die f\u00fcr die unlogische Tabelle erstellt werden, werden automatisch unlogisch.<\/b> Kurz gesagt,<\/p><\/blockquote>\n<p>wird es erheblich schneller sein <b>, aber wenn der DB-Server 'ausf\u00e4llt' \u2013 ist das unangenehm. Doch wie oft passiert das, und kann Ihr ETL-Prozess dies korrekt 'von der Mitte' nach dem 'Wachruf' der DB handhaben?..<\/b>Wenn das nicht der Fall ist und der oben genannte Fall Ihrem \u00e4hnelt \u2013 verwenden Sie<\/p>\n<p>UNLOGGED <code>, aber aktivieren Sie niemals<\/code>dieses Attribut bei realen Tabellen <b>, deren Daten Ihnen wichtig sind.<\/b>1.3. ON COMMIT { DELETE ROWS | DROP }<\/p>\n<h3>Diese Konstruktion erm\u00f6glicht es, bei der Erstellung der Tabelle ein automatisches Verhalten beim Abschluss der Transaktion festzulegen.<\/h3>\n<p>\nIch habe bereits oben geschrieben, dass er generiert<\/p>\n<p>\u00dcber <code>BEIMEN WIDMEN <b>L\u00d6SCHEN<\/b><\/code> , w\u00e4hrend es mit <code>DROP TABLE<\/code>interessanter aussieht \u2013 hier wird generiert <code>BEIMEN WIDMEN <b>ZEILE L\u00d6SCHEN<\/b><\/code> TRUNCATE TABLE <code>Da die gesamte Infrastruktur zur Speicherung der Metadaten der tempor\u00e4ren Tabelle genau die gleiche wie die der normalen ist, ist<\/code>.<\/p>\n<p>Da die gesamte Infrastruktur zur Speicherung der Metadaten tempor\u00e4rer Tabellen genau so ist wie bei regul\u00e4ren Tabellen, ist <b>Das st\u00e4ndige Erstellen und L\u00f6schen von tempor\u00e4ren Tabellen f\u00fchrt zu einer erheblichen \"Aufbl\u00e4hung\" der Systemtabellen.<\/b> pg_class, pg_attribute, pg_attrdef, pg_depend,\u2026<\/p>\n<p>Stellen Sie sich vor, Sie haben einen Worker mit einer direkten Verbindung zur Datenbank, der jede Sekunde eine neue Transaktion \u00f6ffnet, eine tempor\u00e4re Tabelle erstellt, f\u00fcllt, verarbeitet und l\u00f6scht\u2026 Der M\u00fcll in den Systemtabellen wird sich anh\u00e4ufen und es gibt unn\u00f6tige Verz\u00f6gerungen bei jeder Operation.<\/p>\n<p>Im Grunde genommen, so sollte man das nicht machen! In diesem Fall ist es viel effizienter <code>CREATE TEMPORARY TABLE x ... ON COMMIT DELETE ROWS<\/code> au\u00dferhalb des Transaktionszyklus zu erstellen \u2014 dann existieren die Tabellen bereits zu Beginn jeder neuen Transaktion. <b>Sie wird existieren<\/b> (wir sparen den Aufruf <code>ERSTELLEN<\/code>), aber <b>sie wird leer sein<\/b>, dank <code>TRUNCATE<\/code> (diesen Aufruf haben wir ebenfalls gespart) am Ende der vorherigen Transaktion.<\/p>\n<h3>1.4. LIKE\u2026 INCLUDING \u2026<\/h3>\n<p>\nIch habe zu Beginn erw\u00e4hnt, dass ein typischer Anwendungsfall f\u00fcr tempor\u00e4re Tabellen verschiedene Arten von Importen sind \u2014 und der Entwickler kopiert m\u00fcde die Liste der Felder der Zieltabelle in die Deklaration seiner tempor\u00e4ren Tabelle\u2026<\/p>\n<p>Aber Faulheit ist der Motor des Fortschritts! Daher <b>kann eine neue Tabelle \"nach Muster\"<\/b> viel einfacher erstellt werden:<\/p>\n<pre><code class=\"sql\">CREATE TEMPORARY TABLE import_table(\n  LIKE target_table\n);<\/code><\/pre>\n<p>\nDa es m\u00f6glich ist, in diese Tabelle eine gro\u00dfe Menge an Daten zu generieren, wird die Suche darin alles andere als schnell sein. Aber dagegen gibt es eine traditionelle L\u00f6sung \u2013 Indizes! Und ja, <b>auch tempor\u00e4re Tabellen k\u00f6nnen Indizes haben.<\/b>.<\/p>\n<p>Da oft die ben\u00f6tigten Indizes mit den Indizes der Zieltabelle \u00fcbereinstimmen, kann man einfach schreiben: <code>WIE target_table <b>EINSCHLIESSLICH INDEXE<\/b><\/code>.<\/p>\n<p>Wenn Sie auch <code>DEFAULT<\/code>-Werte (zum Beispiel zur Auff\u00fcllung der Werte des Prim\u00e4rschl\u00fcssels) ben\u00f6tigen, k\u00f6nnen Sie <code>WIE target_table <b>EINSCHLIE\u00dfLICH VORGABEN<\/b><\/code>nutzen. Oder einfach \u2013 <code>WIE target_table <b>EINSCHLIE\u00dfLICH ALLER<\/b><\/code> \u2014 kopiert die Defaults, Indizes, Constraints,\u2026<\/p>\n<p>Aber hier muss man schon verstehen, dass, wenn Sie die Importtabelle gleich mit Indizes erstellt haben, die Daten\u00fcbertragung l\u00e4nger dauern wird <b>, als wenn Sie zuerst alles importieren und dann die Indizes anwenden \u2013 schauen Sie sich als Beispiel an, wie das gemacht wird von<\/b>Im Allgemeinen, <noindex><a rel=\"nofollow\" href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/12\/app-pgdump\">pg_dump<\/a><\/noindex>.<\/p>\n<p>RTFM <noindex><a rel=\"nofollow\" href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/12\/sql-createtable\">2. Wie schreibt man?<\/a><\/noindex>!<\/p>\n<h2>Ich sage es einfach \u2013 benutzen Sie<\/h2>\n<p>\n-Stream anstelle von \"Batch\" <code><noindex><a rel=\"nofollow\" href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/12\/sql-copy\">COPY<\/a><\/noindex><\/code>das beschleunigt um ein Vielfaches. <code>INSERT<\/code>, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.citusdata.com\/blog\/2017\/11\/08\/faster-bulk-loading-in-postgresql-with-copy\/\">Man kann sogar direkt aus einer vorher formatierten Datei.<\/a><\/noindex>3. Wie verarbeitet man?<\/p>\n<h2>Lassen Sie uns also annehmen, unser Einstieg sieht etwa so aus:<\/h2>\n<p>\nSie haben in Ihrer Datenbank eine Tabelle mit Kundendaten mit<\/p>\n<ul>\n<li>1 Million Datens\u00e4tzen. <b>Jeden Tag sendet Ihnen der Kunde ein neues<\/b><\/li>\n<li>vollst\u00e4ndiges \"Abbild\". <b>Aus Erfahrung wissen Sie, dass es von Mal zu Mal<\/b><\/li>\n<li>aus Erfahrung wissen Sie, dass es von Mal zu Mal <b>Es werden nicht mehr als 10.000 Datens\u00e4tze ge\u00e4ndert<\/b><\/li>\n<\/ul>\n<p>\nEin klassisches Beispiel f\u00fcr eine solche Situation ist <noindex><a rel=\"nofollow\" href=\"https:\/\/www.gnivc.ru\/technical_support\/classifiers_reference\/kladr\/\">die KLGDR-Datenbank<\/a><\/noindex> \u2014 es gibt viele Adressen, aber in jeder w\u00f6chentlichen Exportdatei gibt es nur sehr wenige \u00c4nderungen (Umbenennungen von Orten, Zusammenlegungen von Stra\u00dfen, das Erscheinen neuer Geb\u00e4ude), selbst im Ma\u00dfstab des ganzen Landes.<\/p>\n<h3>3.1. Algorithmus f\u00fcr die vollst\u00e4ndige Synchronisation<\/h3>\n<p>\nUm es einfach zu halten, nehmen wir an, dass Sie die Daten nicht einmal umstrukturieren m\u00fcssen \u2014 bringen Sie die Tabelle einfach in die gew\u00fcnschte Form, das hei\u00dft:<\/p>\n<ul>\n<li><b>l\u00f6schen<\/b> alles, was nicht mehr existiert<\/li>\n<li><b>aktualisieren<\/b> alles, was bereits vorhanden war und aktualisiert werden muss<\/li>\n<li><b>einf\u00fcgen<\/b> alles, was noch nicht vorhanden war<\/li>\n<\/ul>\n<p>\nWarum sollten diese Operationen genau in dieser Reihenfolge durchgef\u00fchrt werden? Weil auf diese Weise die Gr\u00f6\u00dfe der Tabelle minimal wachsen wird (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/tensor\/blog\/491366\/\">denke an MVCC!<\/a><\/noindex>).<\/p>\n<h4>DELETE FROM dst<\/h4>\n<p>\nNat\u00fcrlich kann man auch mit nur zwei Operationen auskommen:<\/p>\n<ul>\n<li><b>l\u00f6schen<\/b> (<code>DELETE<\/code>) tats\u00e4chlich alles<\/li>\n<li><b>einf\u00fcgen<\/b> alles aus dem neuen Bild<\/li>\n<\/ul>\n<p>\nAber dabei wird dank MVCC <b>die Gr\u00f6\u00dfe der Tabelle genau doppelt so gro\u00df<\/b>! +1 Million Datens\u00e4tze in der Tabelle durch das Aktualisieren von 10.000 \u2014 das ist eine bescheidene \u00dcberfl\u00fcssigkeit\u2026<\/p>\n<h4>TRUNCATE dst<\/h4>\n<p>\nEin erfahrener Entwickler wei\u00df, dass man die gesamte Tabelle recht kosteng\u00fcnstig bereinigen kann:<\/p>\n<ul>\n<li><b>bereinigen<\/b> (<code>TRUNCATE<\/code>) die gesamte Tabelle<\/li>\n<li><b>einf\u00fcgen<\/b> alles aus dem neuen Bild<\/li>\n<\/ul>\n<p>\nDie Methode ist effektiv, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/tensor\/blog\/481866\/\">manchmal durchaus anwendbar<\/a><\/noindex>, aber es gibt ein Problem\u2026 Das Einf\u00fcllen von 1 Million Datens\u00e4tzen wird lange dauern, daher k\u00f6nnen wir es uns nicht leisten, die Tabelle w\u00e4hrend dieser Zeit leer zu lassen (wie es ohne eine umschlie\u00dfende Transaktion geschehen w\u00fcrde).<\/p>\n<p>Das bedeutet:<\/p>\n<ul>\n<li>wir beginnen mit einer <b>langwierigen Transaktion<\/b><\/li>\n<li><code>TRUNCATE<\/code> die <b>AccessExclusive<\/b>-Sperre<\/li>\n<li>wir machen lange Einf\u00fcgungen, w\u00e4hrend alle anderen in dieser Zeit <b>nicht einmal <code>SELECT<\/code><\/b><\/li>\n<\/ul>\n<p>\nEs l\u00e4uft etwas schief\u2026<\/p>\n<h4>ALTER TABLE\u2026 RENAME\u2026 \/ DROP TABLE \u2026<\/h4>\n<p>\nEine M\u00f6glichkeit w\u00e4re, alles in eine separate neue Tabelle einzuf\u00fcgen und sie dann einfach in die alte umzubenennen. Zwei unangenehme Kleinigkeiten:<\/p>\n<ul>\n<li>das ist auch <b>AccessExclusive<\/b>, obwohl es deutlich weniger Zeit in Anspruch nimmt<\/li>\n<li>alle Abfragepl\u00e4ne\/Statistiken dieser Tabelle werden zur\u00fcckgesetzt, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/tensor\/blog\/479656\/\">man muss ANALYZE durchf\u00fchren<\/a><\/noindex><\/li>\n<li><b>alle Fremdschl\u00fcssel<\/b> (FK) auf die Tabelle brechen<\/li>\n<\/ul>\n<p>\nEs gab einen WIP-Patch von Simon Riggs, der vorschlug, die <code>ALTER<\/code>-Operation f\u00fcr den Austausch des Tabellenk\u00f6rpers auf Dateiebene durchzuf\u00fchren, ohne die Statistiken und FK zu beeintr\u00e4chtigen, aber er konnte keine Mehrheit bilden.<\/p>\n<h4>DELETE, UPDATE, INSERT<\/h4>\n<p>\nAlso entscheiden wir uns f\u00fcr die nicht-blockierende Variante aus drei Operationen. Fast drei\u2026 Wie machen wir das am effektivsten?<\/p>\n<pre><code class=\"sql\">-- alles wird im Rahmen der Transaktion durchgef\u00fchrt, damit niemand die \"Zwischen\"-Zust\u00e4nde sieht\nBEGIN;\n\n-- tempor\u00e4re Tabelle mit importierten Daten erstellen\nCREATE TEMPORARY TABLE tmp(\n  LIKE dst INCLUDING INDEXES -- wie das Original, einschlie\u00dflich Indizes\n) ON COMMIT DROP; -- au\u00dferhalb der Transaktion brauchen wir sie nicht\n\n-- schnell und effizient die neuen Daten \u00fcber COPY einf\u00fcgen\nCOPY tmp FROM STDIN;\n-- ...\n-- .\n\n-- fehlende Datens\u00e4tze entfernen\nDELETE FROM\n  dst D\nUSING\n  dst X\nLEFT JOIN\n  tmp Y\n    USING(pk1, pk2) -- Felder des Prim\u00e4rschl\u00fcssels\nWHERE\n  (D.pk1, D.pk2) = (X.pk1, X.pk2) AND\n  Y IS NOT DISTINCT FROM NULL; -- \"Anti-Join\"\n\n-- verbleibende Datens\u00e4tze aktualisieren\nUPDATE\n  dst D\nSET\n  (f1, f2, f3) = (T.f1, T.f2, T.f3)\nFROM\n  tmp T\nWHERE\n  (D.pk1, D.pk2) = (T.pk1, T.pk2) AND\n  (D.f1, D.f2, D.f3) IS DISTINCT FROM (T.f1, T.f2, T.f3); -- keine Notwendigkeit, \u00fcbereinstimmende Datens\u00e4tze zu aktualisieren\n\n-- fehlende Datens\u00e4tze einf\u00fcgen\nINSERT INTO\n  dst\nSELECT\n  T.*\nFROM\n  tmp T\nLEFT JOIN\n  dst D\n    USING(pk1, pk2)\nWHERE\n  D IS NOT DISTINCT FROM NULL;\n\nCOMMIT;\n<\/code><\/pre>\n<p><\/p>\n<h3>3.2. Nachbearbeitung des Imports<\/h3>\n<p>\nIm selben KLR m\u00fcssen alle ge\u00e4nderten Eintr\u00e4ge zus\u00e4tzlich durch die Nachbearbeitung geleitet werden \u2013 normalisieren, Schl\u00fcsselw\u00f6rter extrahieren, in die ben\u00f6tigten Strukturen bringen. Aber wie erfahren wir \u2013 <b>was genau ge\u00e4ndert wurde<\/b>, ohne dabei den Synchronisierungscode zu komplizieren, idealerweise ihn \u00fcberhaupt nicht zu ber\u00fchren?<\/p>\n<p>Wenn der Schreibzugriff zum Zeitpunkt der Synchronisierung nur f\u00fcr Ihren Prozess verf\u00fcgbar ist, k\u00f6nnen Sie einen Trigger verwenden, der uns alle \u00c4nderungen sammelt:<\/p>\n<pre><code class=\"sql\">-- Zieltabellen\nCREATE TABLE kladr(...);\nCREATE TABLE kladr_house(...);\n\n-- Tabellen mit der Historie der \u00c4nderungen\nCREATE TABLE kladr$log(\n  ro kladr, -- hier liegen die kompletten Abbildungen der alten\/neuen Datens\u00e4tze\n  rn kladr\n);\n\nCREATE TABLE kladr_house$log(\n  ro kladr_house,\n  rn kladr_house\n);\n\n-- allgemeine Funktion zur Protokollierung von \u00c4nderungen\nCREATE OR REPLACE FUNCTION diff$log() RETURNS trigger AS $$\nDECLARE\n  dst varchar = TG_TABLE_NAME || '$log';\n  stmt text = '';\nBEGIN\n  -- \u00dcberpr\u00fcfung der Notwendigkeit der Protokollierung bei Aktualisierung des Datensatzes\n  IF TG_OP = 'UPDATE' THEN\n    IF NEW IS NOT DISTINCT FROM OLD THEN\n      RETURN NEW;\n    END IF;\n  END IF;\n  -- Erstellung des Protokolleintrags\n  stmt = 'INSERT INTO ' || dst::text || '(ro,rn)VALUES(';\n  CASE TG_OP\n    WHEN 'INSERT' THEN\n      EXECUTE stmt || 'NULL,$1)' USING NEW;\n    WHEN 'UPDATE' THEN\n      EXECUTE stmt || '$1,$2)' USING OLD, NEW;\n    WHEN 'DELETE' THEN\n      EXECUTE stmt || '$1,NULL)' USING OLD;\n  END CASE;\n  RETURN NEW;\nEND;\n$$ LANGUAGE plpgsql;\n<\/code><\/pre>\n<p>\nJetzt k\u00f6nnen wir vor Beginn der Synchronisierung die Trigger anwenden (oder aktivieren \u00fcber <code>ALTER TABLE ... ENABLE TRIGGER ...<\/code>):<\/p>\n<pre><code class=\"sql\">CREATE TRIGGER log\n  AFTER INSERT OR UPDATE OR DELETE\n  ON kladr\n    FOR EACH ROW\n      EXECUTE PROCEDURE diff$log();\n\nCREATE TRIGGER log\n  AFTER INSERT OR UPDATE OR DELETE\n  ON kladr_house\n    FOR EACH ROW\n      EXECUTE PROCEDURE diff$log();\n<\/code><\/pre>\n<p>\nDann extrahieren wir in Ruhe alle ben\u00f6tigten \u00c4nderungen aus den Log-Tabellen und f\u00fchren diese durch zus\u00e4tzliche Verarbeiter.<\/p>\n<h3>3.3. Import von verkn\u00fcpften Datens\u00e4tzen<\/h3>\n<p>\nZuvor haben wir F\u00e4lle betrachtet, in denen die Datenstrukturen von Quelle und Ziel \u00fcbereinstimmen. Aber was tun, wenn der Export aus einem externen System ein Format hat, das von unserer Datenbankstruktur abweicht?<\/p>\n<p>Nehmen wir als Beispiel die Speicherung von Kunden und deren Rechnungen, das klassische \u201eViele-zu-eins\u201c-Szenario:<\/p>\n<pre><code class=\"sql\">CREATE TABLE client(\n  client_id\n    serial\n      PRIMARY KEY\n, inn\n    varchar\n      UNIQUE\n, name\n    varchar\n);\n\nCREATE TABLE invoice(\n  invoice_id\n    serial\n      PRIMARY KEY\n, client_id\n    integer\n      REFERENCES client(client_id)\n, number\n    varchar\n, dt\n    date\n, sum\n    numeric(32,2)\n);<\/code><\/pre>\n<p>\nDer Export aus der externen Quelle kommt in Form von \u201ealles in einem\u201c:<\/p>\n<pre><code class=\"sql\">CREATE TEMPORARY TABLE invoice_import(\n  client_inn\n    varchar\n, client_name\n    varchar\n, invoice_number\n    varchar\n, invoice_dt\n    date\n, invoice_sum\n    numeric(32,2)\n);<\/code><\/pre>\n<p>\nOffensichtlich k\u00f6nnten die Kundendaten in dieser Form dupliziert werden, wobei der Hauptdatensatz die \u201eRechnung\u201c ist:<\/p>\n<pre><code class=\"plaintext\">0123456789;Vasya;A-01;2020-03-16;1000,00\n9876543210;Petya;A-02;2020-03-16;666,00\n0123456789;Vasya;B-03;2020-03-16;9999,00\n<\/code><\/pre>\n<p>\nF\u00fcr das Modell f\u00fcgen wir einfach unsere Testdaten ein, aber denken Sie daran \u2014 <code>COPY<\/code> es ist effektiver!<\/p>\n<pre><code class=\"sql\">INSERT INTO invoice_import\nVALUES\n  ('0123456789', 'Vasya', 'A-01', '2020-03-16', 1000.00)\n, ('9876543210', 'Petya', 'A-02', '2020-03-16', 666.00)\n, ('0123456789', 'Vasya', 'B-03', '2020-03-16', 9999.00);<\/code><\/pre>\n<p>\nZuerst identifizieren wir die \u201eSchnitte\u201c, auf die sich unsere \u201eFakten\u201c beziehen. In unserem Fall beziehen sich die Rechnungen auf die Kunden:<\/p>\n<pre><code class=\"sql\">CREATE TEMPORARY TABLE client_import AS\nSELECT DISTINCT ON(client_inn)\n-- einfach SELECT DISTINCT verwenden, wenn die Daten definitiv konsistent sind\n  client_inn inn\n, client_name \"name\"\nFROM\n  invoice_import;<\/code><\/pre>\n<p>\nUm die Rechnungen korrekt mit den Kunden-IDs zu verkn\u00fcpfen, m\u00fcssen wir diese Identifikatoren zuerst ermitteln oder generieren. F\u00fcgen wir daf\u00fcr die entsprechenden Felder hinzu:<\/p>\n<pre><code class=\"sql\">ALTER TABLE invoice_import ADD COLUMN client_id integer;\nALTER TABLE client_import ADD COLUMN client_id integer;<\/code><\/pre>\n<p>\nWir verwenden die oben beschriebene Methode zur Synchronisierung der Tabellen mit einer kleinen Anpassung \u2013 wir werden nichts in der Zieltabelle aktualisieren oder l\u00f6schen, da der Import der Kunden \u201eappend-only\u201c ist:<\/p>\n<pre><code class=\"sql\">-- wir tragen in die Importtabelle die IDs bereits vorhandener Datens\u00e4tze ein\nUPDATE\n  client_import T\nSET\n  client_id = D.client_id\nFROM\n  client D\nWHERE\n  T.inn = D.inn; -- eindeutiger Schl\u00fcssel\n\n-- wir f\u00fcgen fehlende Datens\u00e4tze ein und tragen deren IDs ein\nWITH ins AS (\n  INSERT INTO client(\n    inn\n  , name\n  )\n  SELECT\n    inn\n  , name\n  FROM\n    client_import\n  WHERE\n    client_id IS NULL -- wenn die ID nicht eingetragen werden konnte\n  RETURNING *\n)\nUPDATE\n  client_import T\nSET\n  client_id = D.client_id\nFROM\n  ins D\nWHERE\n  T.inn = D.inn; -- eindeutiger Schl\u00fcssel\n\n-- wir tragen die IDs der Kunden in den Rechnungsdatens\u00e4tzen ein\nUPDATE\n  invoice_import T\nSET\n  client_id = D.client_id\nFROM\n  client_import D\nWHERE\n  T.client_inn = D.inn; -- anwendungsbezogener Schl\u00fcssel\n<\/code><\/pre>\n<p>\nEigentlich ist das alles \u2014 <code>invoice_import<\/code> nun haben wir das Verkn\u00fcpfungsfeld ausgef\u00fcllt <code>client_id<\/code>, mit dem wir die Rechnung einf\u00fcgen werden.<br \/>\n<br \/>Quelle: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/tensor\/blog\/492464\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043d\u0430\u0431\u043e\u0440\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0440\u0430\u0437\u043d\u044b\u0435 ETL-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b: \u0438\u043c\u043f\u043e\u0440\u0442\u044b, \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 \u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c) \u0447\u0430\u0441\u0442\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u00ab\u0437\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c\u00bb, \u0438 \u0441\u0440\u0430\u0437\u0443 \u0431\u044b\u0441\u0442\u0440\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043e\u0431\u044a\u0435\u043c\u043d\u043e\u0435. \u0422\u0438\u043f\u043e\u0432\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0440\u043e\u0434\u0430 \u0437\u0432\u0443\u0447\u0438\u0442 \u043e\u0431\u044b\u0447\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a: \u00ab\u0412\u043e\u0442 \u0442\u0443\u0442 \u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u0438\u043b\u0430 \u0438\u0437 \u043a\u043b\u0438\u0435\u043d\u0442-\u0431\u0430\u043d\u043a\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u0432\u0448\u0438\u0435 \u043e\u043f\u043b\u0430\u0442\u044b, \u043d\u0430\u0434\u043e \u0438\u0445 \u0431\u044b\u0441\u0442\u0440\u0435\u043d\u044c\u043a\u043e \u0432\u043a\u0430\u0447\u0430\u0442\u044c \u043d\u0430 \u0441\u0430\u0439\u0442 \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u0442\u044c \u043a \u0441\u0447\u0435\u0442\u0430\u043c\u00bb \u041d\u043e \u043a\u043e\u0433\u0434\u0430 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":74954,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-74953","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 4.9.10 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043d\u0430\u0431\u043e\u0440\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0440\u0430\u0437\u043d\u044b\u0435 ETL-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b: \u0438\u043c\u043f\u043e\u0440\u0442\u044b, \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 \u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c) \u0447\u0430\u0441\u0442\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u00ab\u0437\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c\u00bb, \u0438 \u0441\u0440\u0430\u0437\u0443 \u0431\u044b\u0441\u0442\u0440\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043e\u0431\u044a\u0435\u043c\u043d\u043e\u0435. \u0422\u0438\u043f\u043e\u0432\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0440\u043e\u0434\u0430 \u0437\u0432\u0443\u0447\u0438\u0442 \u043e\u0431\u044b\u0447\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a: \u00ab\u0412\u043e\u0442 \u0442\u0443\u0442 \u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u0438\u043b\u0430 \u0438\u0437 \u043a\u043b\u0438\u0435\u043d\u0442-\u0431\u0430\u043d\u043a\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u0432\u0448\u0438\u0435 \u043e\u043f\u043b\u0430\u0442\u044b, \u043d\u0430\u0434\u043e \u0438\u0445 \u0431\u044b\u0441\u0442\u0440\u0435\u043d\u044c\u043a\u043e \u0432\u043a\u0430\u0447\u0430\u0442\u044c \u043d\u0430 \u0441\u0430\u0439\u0442 \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u0442\u044c \u043a \u0441\u0447\u0435\u0442\u0430\u043c\u00bb \u041d\u043e \u043a\u043e\u0433\u0434\u0430\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/dba-gramotno-organizovyvaem-sinhronizaczii-i-importy\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47DBA: \u0433\u0440\u0430\u043c\u043e\u0442\u043d\u043e \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u043c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0438\u043c\u043f\u043e\u0440\u0442\u044b | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043d\u0430\u0431\u043e\u0440\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0440\u0430\u0437\u043d\u044b\u0435 ETL-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b: \u0438\u043c\u043f\u043e\u0440\u0442\u044b, \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 \u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c) \u0447\u0430\u0441\u0442\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u00ab\u0437\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c\u00bb, \u0438 \u0441\u0440\u0430\u0437\u0443 \u0431\u044b\u0441\u0442\u0440\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043e\u0431\u044a\u0435\u043c\u043d\u043e\u0435. \u0422\u0438\u043f\u043e\u0432\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0440\u043e\u0434\u0430 \u0437\u0432\u0443\u0447\u0438\u0442 \u043e\u0431\u044b\u0447\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a: \u00ab\u0412\u043e\u0442 \u0442\u0443\u0442 \u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u0438\u043b\u0430 \u0438\u0437 \u043a\u043b\u0438\u0435\u043d\u0442-\u0431\u0430\u043d\u043a\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u0432\u0448\u0438\u0435 \u043e\u043f\u043b\u0430\u0442\u044b, \u043d\u0430\u0434\u043e \u0438\u0445 \u0431\u044b\u0441\u0442\u0440\u0435\u043d\u044c\u043a\u043e \u0432\u043a\u0430\u0447\u0430\u0442\u044c \u043d\u0430 \u0441\u0430\u0439\u0442 \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u0442\u044c \u043a \u0441\u0447\u0435\u0442\u0430\u043c\u00bb \u041d\u043e \u043a\u043e\u0433\u0434\u0430\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/dba-gramotno-organizovyvaem-sinhronizaczii-i-importy\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-03-22T05:42:22+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-03-22T05:42:22+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47DBA: wir organisieren Synchronisationen und Importe professionell | ProHoster","description":"Bei der komplexen Verarbeitung gro\u00dfer Datens\u00e4tze (verschiedene ETL-Prozesse: Importe, Konvertierungen und Synchronisationen mit externen Quellen) ergibt sich h\u00e4ufig die Notwendigkeit, vor\u00fcbergehend etwas Gro\u00dfes \u201ezu speichern\u201c und sofort schnell zu verarbeiten. Eine typische Aufgabe dieser Art lautet normalerweise etwa so: \u201eHier hat die Buchhaltung die zuletzt eingegangenen Zahlungen aus dem Kundenbank-Programm exportiert, das m\u00fcssen wir schnell auf die Webseite hochladen und mit den Rechnungen verkn\u00fcpfen\u201c Aber wenn","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/dba-gramotno-organizovyvaem-sinhronizaczii-i-importy","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47DBA: \u0433\u0440\u0430\u043c\u043e\u0442\u043d\u043e \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u043c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0438\u043c\u043f\u043e\u0440\u0442\u044b | ProHoster","og:description":"\u041f\u0440\u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043d\u0430\u0431\u043e\u0440\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0440\u0430\u0437\u043d\u044b\u0435 ETL-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b: \u0438\u043c\u043f\u043e\u0440\u0442\u044b, \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 \u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c) \u0447\u0430\u0441\u0442\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u00ab\u0437\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c\u00bb, \u0438 \u0441\u0440\u0430\u0437\u0443 \u0431\u044b\u0441\u0442\u0440\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043e\u0431\u044a\u0435\u043c\u043d\u043e\u0435. \u0422\u0438\u043f\u043e\u0432\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0440\u043e\u0434\u0430 \u0437\u0432\u0443\u0447\u0438\u0442 \u043e\u0431\u044b\u0447\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a: \u00ab\u0412\u043e\u0442 \u0442\u0443\u0442 \u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u0438\u043b\u0430 \u0438\u0437 \u043a\u043b\u0438\u0435\u043d\u0442-\u0431\u0430\u043d\u043a\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u0432\u0448\u0438\u0435 \u043e\u043f\u043b\u0430\u0442\u044b, \u043d\u0430\u0434\u043e \u0438\u0445 \u0431\u044b\u0441\u0442\u0440\u0435\u043d\u044c\u043a\u043e \u0432\u043a\u0430\u0447\u0430\u0442\u044c \u043d\u0430 \u0441\u0430\u0439\u0442 \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u0442\u044c \u043a \u0441\u0447\u0435\u0442\u0430\u043c\u00bb \u041d\u043e \u043a\u043e\u0433\u0434\u0430","og:url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/dba-gramotno-organizovyvaem-sinhronizaczii-i-importy","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-03-22T05:42:22+00:00","article:modified_time":"2020-03-22T05:42:22+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"74953","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 18:04:26","updated":"2022-09-30 13:25:20"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/74953","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=74953"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/74953\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media\/74954"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=74953"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=74953"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=74953"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}