{"id":79467,"date":"2020-04-27T07:42:23","date_gmt":"2020-04-27T05:42:23","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/operativnaya-analitika-v-mikroservisnoj-arhitekture-p%cc%b6o%cc%b6n%cc%b6ya%cc%b6t%cc%b6%cc%b6-%cc%b6i%cc%b6-%cc%b6p%cc%b6r%cc%b6o%cc%b6s%cc%b6t%cc%b6i%cc%b6t%cc%b6%cc%b6-pomoch-i-podskazat-postgres"},"modified":"2020-04-27T07:42:23","modified_gmt":"2020-04-27T05:42:23","slug":"operativnaya-analitika-v-mikroservisnoj-arhitekture-p%cc%b6o%cc%b6n%cc%b6ya%cc%b6t%cc%b6%cc%b6-%cc%b6i%cc%b6-%cc%b6p%cc%b6r%cc%b6o%cc%b6s%cc%b6t%cc%b6i%cc%b6t%cc%b6%cc%b6-pomoch-i-podskazat-postgres","status":"publish","type":"post","link":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/operativnaya-analitika-v-mikroservisnoj-arhitekture-p%cc%b6o%cc%b6n%cc%b6ya%cc%b6t%cc%b6%cc%b6-%cc%b6i%cc%b6-%cc%b6p%cc%b6r%cc%b6o%cc%b6s%cc%b6t%cc%b6i%cc%b6t%cc%b6%cc%b6-pomoch-i-podskazat-postgres","title":{"rendered":"Echtzeit-Analytik in einer Microservices-Architektur: helfen und unterst\u00fctzen Sie bei Postgres FDW.","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Die Microservices-Architektur hat, wie alles im Leben, ihre Vor- und Nachteile. Einige Prozesse werden einfacher, w\u00e4hrend andere komplexer werden. Um schneller auf \u00c4nderungen reagieren zu k\u00f6nnen und eine bessere Skalierbarkeit zu erreichen, m\u00fcssen wir jedoch gewisse Opfer bringen. Eines davon ist die Komplexit\u00e4t der Analyse. W\u00e4hrend in einer Monolith-Anwendung die gesamte operative Analyse auf SQL-Abfragen an einer analytischen Replikation beruhen kann, hat jeder Service in einer Microservices-Architektur seine eigene Datenbank. Es scheint, dass man mit nur einer Abfrage nicht auskommt (oder vielleicht doch?). F\u00fcr alle, die daran interessiert sind, wie wir das Problem der operativen Analyse in unserem Unternehmen gel\u00f6st haben und wie wir gelernt haben, mit dieser L\u00f6sung zu leben \u2013 herzlich willkommen.<\/p>\n<p><img decoding=\"async\" alt=\"Echtzeit-Analytik in einer Microservices-Architektur: helfen und unterst\u00fctzen Sie bei Postgres FDW.\" src=\"\/wp-content\/uploads\/2020\/04\/4296389f06d488999cc023dcaa3027f7.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMein Name ist Pavel Sivasch und ich arbeite bei DomClick im Team, das f\u00fcr die Betreuung des analytischen Data Warehouses zust\u00e4ndig ist. Unsere Arbeit l\u00e4sst sich grob der Datenengineering zuordnen, jedoch ist das Spektrum der Aufgaben deutlich breiter. Es gibt die typischen ETL\/ELT-Prozesse im Datenengineering, die Unterst\u00fctzung und Anpassung von Analysetools sowie die Entwicklung eigener Tools. Insbesondere f\u00fcr die operative Berichterstattung haben wir beschlossen, so zu tun, als h\u00e4tten wir ein monolithisches System, und den Analysten eine zentrale Datenbank bereitzustellen, die alle ben\u00f6tigten Informationen enth\u00e4lt. <noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Wir haben verschiedene Optionen in Betracht gezogen. Man k\u00f6nnte ein vollwertiges Speicher-System aufbauen \u2013 wir haben es sogar ausprobiert, aber ehrlich gesagt ist es uns nicht gelungen, h\u00e4ufige \u00c4nderungen in der Logik mit dem recht langsamen Prozess des Aufbaus des Speichers und der Integration von \u00c4nderungen zu vereinen (wenn jemand es geschafft hat, bitte teilen Sie Ihre Erfahrungen in den Kommentaren mit). Es h\u00e4tte den Analysten gesagt werden k\u00f6nnen: \"Leute, lernt Python und nutzt analytische Instanzen\", aber das w\u00e4re eine zus\u00e4tzliche Anforderung bei der Personalbeschaffung und wir wollten dem, wenn m\u00f6glich, aus dem Weg gehen. Deshalb entschieden wir uns, die Technologie FDW (Foreign Data Wrapper) auszuprobieren: im Grunde ist das ein standardm\u00e4\u00dfiger dblink, der im SQL-Standard vorhanden ist, jedoch mit einer viel benutzerfreundlicheren Schnittstelle. Auf dieser Basis haben wir eine L\u00f6sung entwickelt, die sich schlie\u00dflich bew\u00e4hrt hat und auf der wir stehen geblieben sind. Die Einzelheiten dazu sind das Thema eines eigenen Artikels, vielleicht sogar mehrerer, denn es gibt viel zu erz\u00e4hlen: von der Synchronisierung von Datenbankschemas bis hin zum Zugriffsmanagement und der Anonymisierung personenbezogener Daten. Es sollte auch erw\u00e4hnt werden, dass diese L\u00f6sung keinen Ersatz f\u00fcr echte analytische Datenbanken und Speichersysteme darstellt, sondern lediglich ein spezifisches Problem l\u00f6st.<\/p>\n<p>Auf oberster Ebene sieht das so aus:<\/p>\n<p><img decoding=\"async\" alt=\"Echtzeit-Analytik in einer Microservices-Architektur: helfen und unterst\u00fctzen Sie bei Postgres FDW.\" src=\"\/wp-content\/uploads\/2020\/04\/574da29dfdb40706afe9e817e789a61b.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEs gibt eine PostgreSQL-Datenbank, in der die Benutzer ihre Arbeitsdaten speichern k\u00f6nnen. Das Wichtigste ist, dass \u00fcber FDW analytische Replikate aller Dienste mit dieser Datenbank verbunden sind. Dies erm\u00f6glicht es, Abfragen an mehrere Datenbanken zu richten, unabh\u00e4ngig davon, ob es sich um PostgreSQL, MySQL, MongoDB oder etwas anderes handelt (eine Datei, eine API \u2013 wenn es keinen geeigneten Wrapper gibt, kann man auch seinen eigenen schreiben). Soweit alles klar? Super! Auf Wiedersehen?<\/p>\n<p>Wenn alles so schnell und einfach enden w\u00fcrde, g\u00e4be es wahrscheinlich keinen Artikel.<\/p>\n<p>Es ist wichtig genau zu verstehen, wie PostgreSQL Anfragen an entfernte Server verarbeitet. Das scheint logisch, wird jedoch oft nicht beachtet: PostgreSQL zerlegt eine Anfrage in Teile, die unabh\u00e4ngig auf den entfernten Servern ausgef\u00fchrt werden, sammelt diese Daten und f\u00fchrt die abschlie\u00dfenden Berechnungen selbst durch. Daher h\u00e4ngt die Geschwindigkeit der Anfrage stark davon ab, wie sie geschrieben ist. Es sollte auch erw\u00e4hnt werden: Wenn Daten von einem entfernten Server ankommen, sind sie bereits ohne Indizes, ohne alles, was dem Planner helfen k\u00f6nnte. Das bedeutet, dass nur wir ihm helfen und Hinweise geben k\u00f6nnen. Genau dar\u00fcber m\u00f6chte ich genauer berichten.<\/p>\n<h1>Ein einfacher Abfrageplan und der dazugeh\u00f6rige<\/h1>\n<p>\nUm zu zeigen, wie PostgreSQL eine Abfrage an eine Tabelle mit 6 Millionen Zeilen auf einem entfernten <a class=\"wpil_keyword_link\" href=\"https:\/\/prohoster.info\/de\/server\/dts-dronten\/\"   title=\"Server\" data-wpil-keyword-link=\"linked\"  data-wpil-monitor-id=\"2589\">Server<\/a>, werfen wir einen Blick auf den einfachen Plan.<\/p>\n<pre><code class=\"sql\">erkl\u00e4ren analysieren ausf\u00fchrlich  \nSELECT count(1)\nFROM fdw_schema.table;\n\nAggregation  (Kosten=418383.23..418383.24 Reihen=1 Breite=8) (tats\u00e4chliche Zeit=3857.198..3857.198 Reihen=1 Schleifen=1)\n  Ausgabe: count(1)\n  -&gt;  Fremdscan auf fdw_schema.&quot;table&quot;  (Kosten=100.00..402376.14 Reihen=6402838 Breite=0) (tats\u00e4chliche Zeit=4.874..3256.511 Reihen=6406868 Schleifen=1)\n        Ausgabe: &quot;table&quot;.id, &quot;table&quot;.is_active, &quot;table&quot;.meta, &quot;table&quot;.created_dt\n        Remote SQL: SELECT NULL FROM fdw_schema.table\nPlanungszeit: 0.986 ms\nAusf\u00fchrungszeit: 3857.436 ms<\/code><\/pre>\n<p>\nDie Verwendung der VERBOSE-Anweisung erm\u00f6glicht es, die Abfrage zu sehen, die an den entfernten Server gesendet wird, und die Ergebnisse, die wir f\u00fcr die weitere Verarbeitung erhalten (Zeile RemoteSQL).<\/p>\n<p>Lassen Sie uns einen Schritt weiter gehen und einige Filter zu unserer Abfrage hinzuf\u00fcgen: einen nach <b>boolean<\/b> Feld, einen nach Vorkommen <b>timestamp<\/b> in einem Intervall und einen nach <b>jsonb<\/b>.<\/p>\n<pre><code class=\"sql\">erkl\u00e4ren analysieren ausf\u00fchrlich\nSELECT count(1)\nFROM fdw_schema.table \nWHERE is_active is True\nAND created_dt BETWEEN CURRENT_DATE - INTERVAL '7 month' \nAND CURRENT_DATE - INTERVAL '6 month'\nAND meta-&gt;&gt;'source' = 'test';\n\nAggregation  (Kosten=577487.69..577487.70 Reihen=1 Breite=8) (tats\u00e4chliche Zeit=27473.818..25473.819 Reihen=1 Schleifen=1)\n  Ausgabe: count(1)\n  -&gt;  Fremdscan auf fdw_schema.&quot;table&quot;  (Kosten=100.00..577469.21 Reihen=7390 Breite=0) (tats\u00e4chliche Zeit=31.369..25372.466 Reihen=1360025 Schleifen=1)\n        Ausgabe: &quot;table&quot;.id, &quot;table&quot;.is_active, &quot;table&quot;.meta, &quot;table&quot;.created_dt\n        Filter: ((&quot;table&quot;.is_active IS TRUE) AND ((&quot;table&quot;.meta -&gt;&gt; 'source'::text) = 'test'::text) AND (&quot;table&quot;.created_dt &gt;= (('now'::cstring)::date - '7 mons'::interval)) AND (&quot;table&quot;.created_dt &lt;= ((('now'::cstring)::date)::timestamp mit Zeitzone - '6 mons'::interval)))\n        Reihen entfernt durch Filter: 5046843\n        Remote SQL: SELECT created_dt, is_active, meta FROM fdw_schema.table\nPlanungszeit: 0.665 ms\nAusf\u00fchrungszeit: 27474.118 ms<\/code><\/pre>\n<p>\nHier liegt genau der Punkt, auf den man bei der Erstellung von Abfragen achten sollte. Die Filter wurden nicht an den entfernten Server \u00fcbermittelt, was bedeutet, dass PostgreSQL alle 6 Millionen Zeilen abruft, um sie dann lokal zu filtern (Zeile Filter) und die Aggregation durchzuf\u00fchren. Der Schl\u00fcssel zum Erfolg liegt darin, die Abfrage so zu gestalten, dass die Filter an die entfernte Maschine \u00fcbermittelt werden und wir nur die ben\u00f6tigten Zeilen erhalten und aggregieren. <\/p>\n<h1>Das ist ein bisschen Bullshit<\/h1>\n<p>\nBei Booleans ist alles ganz einfach. Im urspr\u00fcnglichen Abfrage gab es ein Problem mit dem Operator. <b>ist<\/b>. Wenn wir es durch <b>=<\/b>ersetzen, erhalten wir folgendes Ergebnis:<\/p>\n<pre><code class=\"sql\">explain analyze verbose\nSELECT count(1)\nFROM fdw_schema.table\nWHERE is_active = True\nAND created_dt BETWEEN CURRENT_DATE - INTERVAL '7 month' \nAND CURRENT_DATE - INTERVAL '6 month'\nAND meta-&gt;&gt;'source' = 'test';\n\nAggregate  (cost=508010.14..508010.15 rows=1 width=8) (actual time=19064.314..19064.314 rows=1 loops=1)\n  Output: count(1)\n  -&gt;  Foreign Scan on fdw_schema.\"table\"  (cost=100.00..507988.44 rows=8679 width=0) (actual time=33.035..18951.278 rows=1360025 loops=1)\n        Output: \"table\".id, \"table\".is_active, \"table\".meta, \"table\".created_dt\n        Filter: (((\"table\".meta -&gt;&gt; 'source'::text) = 'test'::text) AND (\"table\".created_dt &gt;= (('now'::cstring)::date - '7 mons'::interval)) AND (\"table\".created_dt &lt;= (((&#039;now&#039;::cstring)::date)::timestamp with time zone - &#039;6 mons&#039;::interval)))\n        Rows Removed by Filter: 3567989\n        Remote SQL: SELECT created_dt, meta FROM fdw_schema.table WHERE (is_active)\nPlanning time: 0.834 ms\nExecution time: 19064.534 ms<\/code><\/pre>\n<p>\nWie Sie sehen k\u00f6nnen, wurde der Filter an den Remote-Server gesendet, und die Ausf\u00fchrungszeit wurde von 27 auf 19 Sekunden reduziert. <\/p>\n<p>Es ist zu beachten, dass der Operator <b>ist<\/b> sich von dem Operator <b>=<\/b> darin unterscheidet, dass er mit dem Wert Null umgehen kann. Das bedeutet, dass <b>is not True<\/b> im Filter die Werte False und Null bel\u00e4sst, w\u00e4hrend <b>!= True<\/b> nur die Werte False bel\u00e4sst. Daher sollten bei der Ersetzung des Operators <b>is not<\/b> zwei Bedingungen mit dem Operator OR im Filter \u00fcbergeben werden, zum Beispiel: <b>WHERE (col != True) OR (col is null)<\/b>.<\/p>\n<p>Nachdem wir uns mit Boolean auseinandergesetzt haben, machen wir weiter. Lassen Sie uns den Filter f\u00fcr den booleschen Wert zun\u00e4chst auf die urspr\u00fcngliche Form zur\u00fccksetzen, um die Auswirkungen anderer \u00c4nderungen unabh\u00e4ngig zu betrachten.<\/p>\n<h1>timestamptz? hz<\/h1>\n<p>\nIn der Tat muss man oft experimentieren, um herauszufinden, wie man eine Abfrage korrekt formuliert, die entfernte Server einbezieht, und erst danach sucht man nach einer Erkl\u00e4rung, warum es so ist. Im Internet findet man dazu sehr wenige Informationen. So haben wir in unseren Experimenten festgestellt, dass der Filter nach einem festen Datum problemlos auf den entfernten Server \u00fcbertragen wird, w\u00e4hrend dies nicht funktioniert, wenn wir das Datum dynamisch festlegen wollen, beispielsweise mit now() oder CURRENT_DATE. In unserem Beispiel haben wir einen solchen Filter hinzugef\u00fcgt, um sicherzustellen, dass die Spalte created_at Daten enth\u00e4lt, die genau einen Monat in der Vergangenheit liegen (BETWEEN CURRENT_DATE - INTERVAL '7 month' AND CURRENT_DATE - INTERVAL '6 month'). Was haben wir in diesem Fall unternommen?<\/p>\n<pre><code class=\"sql\">erkl\u00e4ren analysieren ausf\u00fchrlich\nSELECT count(1)\nFROM fdw_schema.tabelle \nWHERE is_active is True\nAND created_dt &gt;= (SELECT CURRENT_DATE::timestamptz - INTERVAL '7 Monate') \nAND created_dt &gt;'source' = 'test';\n\nAggregate  (cost=306875.17..306875.18 rows=1 width=8) (actual time=4789.114..4789.115 rows=1 loops=1)\n  Ausgabe: count(1)\n  InitPlan 1 (liefert $0)\n    -&gt;  Ergebnis  (cost=0.00..0.02 rows=1 width=8) (actual time=0.007..0.008 rows=1 loops=1)\n          Ausgabe: ((('jetzt'::cstring)::date)::timestamp with Zeitzone - '7 Monate'::interval)\n  InitPlan 2 (liefert $1)\n    -&gt;  Ergebnis  (cost=0.00..0.02 rows=1 width=8) (actual time=0.002..0.002 rows=1 loops=1)\n          Ausgabe: ((('jetzt'::cstring)::date)::timestamp with Zeitzone - '6 Monate'::interval)\n  -&gt;  ForeignScan auf fdw_schema.\"tabelle\"  (cost=100.02..306874.86 rows=105 width=0) (actual time=23.475..4681.419 rows=1360025 loops=1)\n        Ausgabe: \"tabelle\".id, \"tabelle\".is_active, \"tabelle\".meta, \"tabelle\".created_dt\n        Filter: ((\"tabelle\".is_active IS TRUE) AND ((\"tabelle\".meta -&gt;&gt;'source'::text) = 'test'::text))\n        Entfernte Zeilen durch Filter: 76934\n        Remote SQL: SELECT is_active, meta FROM fdw_schema.tabelle WHERE ((created_dt &gt;= $1::timestamp with Zeitzone)) AND ((created_dt &lt; $2::timestamp with Zeitzone))\nPlanungszeit: 0.703 ms\nAusf\u00fchrungszeit: 4789.379 ms<\/code><\/pre>\n<p>\nWir haben dem Planer geraten, das Datum im Unterabfrage vorab zu berechnen und die vorbereitete Variable bereits im Filter zu verwenden. Und dieser Hinweis hat gro\u00dfartige Ergebnisse geliefert, die Abfrage ist fast sechsmal schneller geworden!<\/p>\n<p>Es ist wichtig, darauf zu achten: Der Datentyp in der Unterabfrage muss mit dem Feldtyp \u00fcbereinstimmen, nach dem wir filtern. Andernfalls wird der Planer entscheiden, dass die Typen unterschiedlich sind und zun\u00e4chst alle Daten abrufen, um sie dann lokal zu filtern.<\/p>\n<p>Setzen wir den Datumsfilter auf den urspr\u00fcnglichen Wert zur\u00fcck.<\/p>\n<h1>Freddy vs. Jsonb<\/h1>\n<p>\nDie booleschen Felder und Datumsangaben haben unseren Abfrageprozess bereits erheblich beschleunigt, jedoch blieb ein weiterer Datentyp zu optimieren. Die Herausforderung bei der Filterung bleibt, ehrlich gesagt, bestehen, obwohl wir auch hier Fortschritte gemacht haben. So haben wir den Filter \u00fcbermittelt f\u00fcr <b>jsonb<\/b> das Feld auf einen Remote-Server.<\/p>\n<pre><code class=\"sql\">erkl\u00e4ren analysieren ausf\u00fchrlich\nSELECT count(1)\nFROM fdw_schema.table \nWHERE is_active is True\nAND created_dt BETWEEN CURRENT_DATE - INTERVAL '7 Monate' \nAND CURRENT_DATE - INTERVAL '6 Monate'\nAND meta @&gt; '{\"source\":\"test\"}'::jsonb;\n\nAggregate  (cost=245463.60..245463.61 rows=1 width=8) (tats\u00e4chliche Zeit=6727.589..6727.590 rows=1 loops=1)\n  Ausgabe: count(1)\n  -&gt;  Foreign Scan auf fdw_schema.\"table\"  (cost=1100.00..245459.90 rows=1478 width=0) (tats\u00e4chliche Zeit=16.213..6634.794 rows=1360025 loops=1)\n        Ausgabe: \"table\".id, \"table\".is_active, \"table\".meta, \"table\".created_dt\n        Filter: ((\"table\".is_active IS TRUE) AND (\"table\".created_dt &gt;= (('jetzt'::cstring)::date - '7 mons'::interval)) AND (\"table\".created_dt &lt;= ((('jetzt'::cstring)::date)::timestamp mit Zeitzone - '6 mons'::interval)))\n        Entfernte Zeilen durch Filter: 619961\n        Remote SQL: SELECT created_dt, is_active FROM fdw_schema.table WHERE ((meta @&gt; '{\"source\": \"test\"}'::jsonb))\nPlanungszeit: 0.747 ms\nAusf\u00fchrungszeit: 6727.815 ms<\/code><\/pre>\n<p>\nAnstelle von Filteroperatoren sollte der Existenzoperator eines <b>jsonb<\/b> anderen verwendet werden. 7 Sekunden statt urspr\u00fcnglicher 29. Bisher ist dies die einzige erfolgreiche Methode zur \u00dcbertragung der Filter. <b>jsonb<\/b> zu einem entfernten Server, aber hier gibt es eine wichtige Einschr\u00e4nkung: Wir verwenden die Version 9.6 der Datenbank, planen jedoch, bis Ende April die letzten Tests abzuschlie\u00dfen und auf Version 12 umzusteigen. Sobald wir aktualisieren, werden wir berichten, wie sich das ausgewirkt hat, denn es gibt viele \u00c4nderungen, auf die wir hoffen: json_path, neues Verhalten von CTE, push down (bereits seit Version 10 vorhanden). Wir sind sehr gespannt darauf, das so schnell wie m\u00f6glich auszuprobieren.<\/p>\n<h1>Finish him<\/h1>\n<p>\nWir haben \u00fcberpr\u00fcft, wie sich jede \u00c4nderung einzeln auf die Abfragegeschwindigkeit auswirkt. Lassen Sie uns nun sehen, was passiert, wenn alle drei Filter korrekt geschrieben sind.<\/p>\n<pre><code class=\"sql\">explain analyze verbose\nSELECT count(1)\nFROM fdw_schema.table \nWHERE is_active = True\nAND created_dt &gt;= (SELECT CURRENT_DATE::timestamptz - INTERVAL '7 month') \nAND created_dt  '{\"source\":\"test\"}'::jsonb;\n\nAggregate  (cost=322041.51..322041.52 rows=1 width=8) (actual time=2278.867..2278.867 rows=1 loops=1)\n  Output: count(1)\n  InitPlan 1 (returns $0)\n    -&gt;  Result  (cost=0.00..0.02 rows=1 width=8) (actual time=0.010..0.010 rows=1 loops=1)\n          Output: ((('now'::cstring)::date)::timestamp with time zone - '7 mons'::interval)\n  InitPlan 2 (returns $1)\n    -&gt;  Result  (cost=0.00..0.02 rows=1 width=8) (actual time=0.003..0.003 rows=1 loops=1)\n          Output: ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)\n  -&gt;  Foreign Scan on fdw_schema.\"table\"  (cost=100.02..322041.41 rows=25 width=0) (actual time=8.597..2153.809 rows=1360025 loops=1)\n        Output: \"table\".id, \"table\".is_active, \"table\".meta, \"table\".created_dt\n        Remote SQL: SELECT NULL FROM fdw_schema.table WHERE (is_active) AND ((created_dt &gt;= $1::timestamp with time zone)) AND ((created_dt  '{\"source\": \"test\"}'::jsonb))\nPlanning time: 0.820 ms\nExecution time: 2279.087 ms<\/code><\/pre>\n<p>\nJa, die Abfrage sieht komplizierter aus, das ist eine notwendige Belastung, aber die Ausf\u00fchrungszeit betr\u00e4gt 2 Sekunden, was mehr als 10-mal schneller ist! Und dabei sprechen wir von einer einfachen Abfrage an einem relativ kleinen Datensatz. Bei realen Abfragen haben wir Zuw\u00e4chse von mehreren hunderttausend Mal erhalten.<\/p>\n<p>Zusammenfassend: Wenn Sie PostgreSQL mit FDW verwenden, \u00fcberpr\u00fcfen Sie immer, ob alle Filter an den entfernten Server gesendet werden, und Sie werden gl\u00fccklich sein... zumindest bis Sie zu Joins zwischen Tabellen aus verschiedenen erreichen. <a class=\"wpil_keyword_link\" href=\"https:\/\/prohoster.info\/de\/server\/\"   title=\"Server\" data-wpil-keyword-link=\"linked\"  data-wpil-monitor-id=\"1482\">Server<\/a>. Aber das ist schon eine Geschichte f\u00fcr einen anderen Artikel.<\/p>\n<p>Danke f\u00fcr Ihre Aufmerksamkeit! Ich freue mich \u00fcber Fragen, Kommentare und Geschichten \u00fcber Ihre Erfahrungen in den Kommentaren.<br \/>\n<br \/>Quelle: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/domclick\/blog\/498018\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430, \u043a\u0430\u043a \u0438 \u0432\u0441\u0435 \u0432 \u044d\u0442\u043e\u043c \u043c\u0438\u0440\u0435, \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0438 \u043f\u043b\u044e\u0441\u044b \u0438 \u0441\u0432\u043e\u0438 \u043c\u0438\u043d\u0443\u0441\u044b. \u041e\u0434\u043d\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u0441 \u043d\u0435\u0439 \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u043f\u0440\u043e\u0449\u0435, \u0434\u0440\u0443\u0433\u0438\u0435 \u2014 \u0441\u043b\u043e\u0436\u043d\u0435\u0435. \u0418 \u0432 \u0443\u0433\u043e\u0434\u0443 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0438 \u043b\u0443\u0447\u0448\u0435\u0439 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0438\u043d\u043e\u0441\u0438\u0442\u044c \u0441\u0432\u043e\u0438 \u0436\u0435\u0440\u0442\u0432\u044b. \u041e\u0434\u043d\u0430 \u0438\u0437 \u043d\u0438\u0445 \u2014 \u0443\u0441\u043b\u043e\u0436\u043d\u0435\u043d\u0438\u0435 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438. \u0415\u0441\u043b\u0438 \u0432 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0435 \u0432\u0441\u044e \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u0443\u044e \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u0441\u0432\u0435\u0441\u0442\u0438 \u043a SQL \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c \u043a \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0440\u0435\u043f\u043b\u0438\u043a\u0435, [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":79468,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-79467","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=\"\u041c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430, \u043a\u0430\u043a \u0438 \u0432\u0441\u0435 \u0432 \u044d\u0442\u043e\u043c \u043c\u0438\u0440\u0435, \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0438 \u043f\u043b\u044e\u0441\u044b \u0438 \u0441\u0432\u043e\u0438 \u043c\u0438\u043d\u0443\u0441\u044b. \u041e\u0434\u043d\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u0441 \u043d\u0435\u0439 \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u043f\u0440\u043e\u0449\u0435, \u0434\u0440\u0443\u0433\u0438\u0435 \u2014 \u0441\u043b\u043e\u0436\u043d\u0435\u0435. \u0418 \u0432 \u0443\u0433\u043e\u0434\u0443 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0438 \u043b\u0443\u0447\u0448\u0435\u0439 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0438\u043d\u043e\u0441\u0438\u0442\u044c \u0441\u0432\u043e\u0438 \u0436\u0435\u0440\u0442\u0432\u044b. \u041e\u0434\u043d\u0430 \u0438\u0437 \u043d\u0438\u0445 \u2014 \u0443\u0441\u043b\u043e\u0436\u043d\u0435\u043d\u0438\u0435 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438. \u0415\u0441\u043b\u0438 \u0432 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0435 \u0432\u0441\u044e \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u0443\u044e \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u0441\u0432\u0435\u0441\u0442\u0438 \u043a SQL \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c \u043a \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0440\u0435\u043f\u043b\u0438\u043a\u0435,\" \/>\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\/operativnaya-analitika-v-mikroservisnoj-arhitekture-p%cc%b6o%cc%b6n%cc%b6ya%cc%b6t%cc%b6%cc%b6-%cc%b6i%cc%b6-%cc%b6p%cc%b6r%cc%b6o%cc%b6s%cc%b6t%cc%b6i%cc%b6t%cc%b6%cc%b6-pomoch-i-podskazat-postgres\" \/>\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\udd47\u041e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430 \u0432 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435: \u043f\u0336\u043e\u0336\u043d\u0336\u044f\u0336\u0442\u0336\u044c\u0336 \u0336\u0438\u0336 \u0336\u043f\u0336\u0440\u0336\u043e\u0336\u0441\u0336\u0442\u0336\u0438\u0336\u0442\u0336\u044c\u0336 \u043f\u043e\u043c\u043e\u0447\u044c \u0438 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u0430\u0442\u044c Postgres FDW | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430, \u043a\u0430\u043a \u0438 \u0432\u0441\u0435 \u0432 \u044d\u0442\u043e\u043c \u043c\u0438\u0440\u0435, \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0438 \u043f\u043b\u044e\u0441\u044b \u0438 \u0441\u0432\u043e\u0438 \u043c\u0438\u043d\u0443\u0441\u044b. \u041e\u0434\u043d\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u0441 \u043d\u0435\u0439 \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u043f\u0440\u043e\u0449\u0435, \u0434\u0440\u0443\u0433\u0438\u0435 \u2014 \u0441\u043b\u043e\u0436\u043d\u0435\u0435. \u0418 \u0432 \u0443\u0433\u043e\u0434\u0443 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0438 \u043b\u0443\u0447\u0448\u0435\u0439 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0438\u043d\u043e\u0441\u0438\u0442\u044c \u0441\u0432\u043e\u0438 \u0436\u0435\u0440\u0442\u0432\u044b. \u041e\u0434\u043d\u0430 \u0438\u0437 \u043d\u0438\u0445 \u2014 \u0443\u0441\u043b\u043e\u0436\u043d\u0435\u043d\u0438\u0435 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438. \u0415\u0441\u043b\u0438 \u0432 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0435 \u0432\u0441\u044e \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u0443\u044e \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u0441\u0432\u0435\u0441\u0442\u0438 \u043a SQL \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c \u043a \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0440\u0435\u043f\u043b\u0438\u043a\u0435,\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/operativnaya-analitika-v-mikroservisnoj-arhitekture-p%cc%b6o%cc%b6n%cc%b6ya%cc%b6t%cc%b6%cc%b6-%cc%b6i%cc%b6-%cc%b6p%cc%b6r%cc%b6o%cc%b6s%cc%b6t%cc%b6i%cc%b6t%cc%b6%cc%b6-pomoch-i-podskazat-postgres\" \/>\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-04-27T05:42:23+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-04-27T05:42:23+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\udd47Operative Analytik in der Mikrodienste-Architektur: helfen und beraten Postgres FDW | ProHoster","description":"Die Mikrodienste-Architektur hat, wie alles auf der Welt, ihre Vor- und Nachteile. Einige Prozesse werden damit einfacher, andere komplizierter. Und im Namen der \u00c4nderungsge-schwindigkeit und besseren Skalierbarkeit muss man Opfer bringen. Eines davon ist die Komplexit\u00e4t der Analytik. W\u00e4hrend im Monolithen die gesamte operative Analytik auf SQL-Abfragen zur analytischen Replikation reduziert werden kann,","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/operativnaya-analitika-v-mikroservisnoj-arhitekture-p%cc%b6o%cc%b6n%cc%b6ya%cc%b6t%cc%b6%cc%b6-%cc%b6i%cc%b6-%cc%b6p%cc%b6r%cc%b6o%cc%b6s%cc%b6t%cc%b6i%cc%b6t%cc%b6%cc%b6-pomoch-i-podskazat-postgres","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\udd47\u041e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430 \u0432 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435: \u043f\u0336\u043e\u0336\u043d\u0336\u044f\u0336\u0442\u0336\u044c\u0336 \u0336\u0438\u0336 \u0336\u043f\u0336\u0440\u0336\u043e\u0336\u0441\u0336\u0442\u0336\u0438\u0336\u0442\u0336\u044c\u0336 \u043f\u043e\u043c\u043e\u0447\u044c \u0438 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u0430\u0442\u044c Postgres FDW | ProHoster","og:description":"\u041c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430, \u043a\u0430\u043a \u0438 \u0432\u0441\u0435 \u0432 \u044d\u0442\u043e\u043c \u043c\u0438\u0440\u0435, \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0438 \u043f\u043b\u044e\u0441\u044b \u0438 \u0441\u0432\u043e\u0438 \u043c\u0438\u043d\u0443\u0441\u044b. \u041e\u0434\u043d\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u0441 \u043d\u0435\u0439 \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u043f\u0440\u043e\u0449\u0435, \u0434\u0440\u0443\u0433\u0438\u0435 \u2014 \u0441\u043b\u043e\u0436\u043d\u0435\u0435. \u0418 \u0432 \u0443\u0433\u043e\u0434\u0443 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0438 \u043b\u0443\u0447\u0448\u0435\u0439 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0438\u043d\u043e\u0441\u0438\u0442\u044c \u0441\u0432\u043e\u0438 \u0436\u0435\u0440\u0442\u0432\u044b. \u041e\u0434\u043d\u0430 \u0438\u0437 \u043d\u0438\u0445 \u2014 \u0443\u0441\u043b\u043e\u0436\u043d\u0435\u043d\u0438\u0435 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438. \u0415\u0441\u043b\u0438 \u0432 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0435 \u0432\u0441\u044e \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u0443\u044e \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u0441\u0432\u0435\u0441\u0442\u0438 \u043a SQL \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c \u043a \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0440\u0435\u043f\u043b\u0438\u043a\u0435,","og:url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/operativnaya-analitika-v-mikroservisnoj-arhitekture-p%cc%b6o%cc%b6n%cc%b6ya%cc%b6t%cc%b6%cc%b6-%cc%b6i%cc%b6-%cc%b6p%cc%b6r%cc%b6o%cc%b6s%cc%b6t%cc%b6i%cc%b6t%cc%b6%cc%b6-pomoch-i-podskazat-postgres","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-04-27T05:42:23+00:00","article:modified_time":"2020-04-27T05:42:23+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"79467","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 16:37:24","updated":"2026-02-09 21:38:01"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/79467","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=79467"}],"version-history":[{"count":2,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/79467\/revisions"}],"predecessor-version":[{"id":159871,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/79467\/revisions\/159871"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media\/79468"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=79467"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=79467"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=79467"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}