{"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\/fr\/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":"Analyse op\u00e9rationnelle dans une architecture microservices : p\u0336o\u0336n\u0336y\u0336e\u0336t\u0336 \u0336e\u0336t\u0336 \u0336a\u0336i\u0336d\u0336e\u0336 des conseils pour Postgres FDW","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>L'architecture microservices, comme tout dans ce monde, a ses avantages et ses inconv\u00e9nients. Certains processus deviennent plus simples avec elle, d'autres, plus compliqu\u00e9s. Et en faveur de la rapidit\u00e9 des changements et d'une meilleure scalabilit\u00e9, il faut faire des sacrifices. L'un d'eux est la complexit\u00e9 de l'analyse. Alors que dans un monolithe, toute l'analyse op\u00e9rationnelle peut \u00eatre r\u00e9duite \u00e0 des requ\u00eates SQL sur une r\u00e9plique analytique, dans une architecture multi-services, chaque service poss\u00e8de sa propre base de donn\u00e9es et il semble qu'une seule requ\u00eate ne suffise pas (ou peut-\u00eatre que si ?). Pour ceux qui s'int\u00e9ressent \u00e0 la mani\u00e8re dont nous avons r\u00e9solu le probl\u00e8me de l'analyse op\u00e9rationnelle dans notre entreprise et comment nous avons appris \u00e0 vivre avec cette solution \u2014 bienvenue.<\/p>\n<p><img decoding=\"async\" alt=\"Analyse op\u00e9rationnelle dans une architecture microservices : p\u0336o\u0336n\u0336y\u0336e\u0336t\u0336 \u0336e\u0336t\u0336 \u0336a\u0336i\u0336d\u0336e\u0336 des conseils pour Postgres FDW\" src=\"\/wp-content\/uploads\/2020\/04\/4296389f06d488999cc023dcaa3027f7.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nJe m'appelle Pavel Sivas, et chez DomClick, je fais partie d'une \u00e9quipe qui est responsable de l'accompagnement de l'entrep\u00f4t de donn\u00e9es analytiques. On peut qualifier notre activit\u00e9 de g\u00e9nie des donn\u00e9es, mais en r\u00e9alit\u00e9, le champ de t\u00e2ches est beaucoup plus large. Il y a des t\u00e2ches normales de g\u00e9nie des donn\u00e9es telles que l'ETL\/ELT, le support et l'adaptation des outils pour l'analyse des donn\u00e9es, ainsi que le d\u00e9veloppement de nos propres outils. En particulier, pour le reporting op\u00e9rationnel, nous avons d\u00e9cid\u00e9 de \u00ab faire semblant \u00bb d'avoir un monolithe et de donner aux analystes une base unique contenant toutes les donn\u00e9es dont ils ont besoin. <noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>En r\u00e9alit\u00e9, nous avons envisag\u00e9 diff\u00e9rentes options. Nous aurions pu construire un v\u00e9ritable entrep\u00f4t de donn\u00e9es \u2014 nous avons m\u00eame essay\u00e9, mais honn\u00eatement, nous n'avons pas r\u00e9ussi \u00e0 harmoniser les changements fr\u00e9quents dans la logique avec le processus de construction de l'entrep\u00f4t et la mise \u00e0 jour des donn\u00e9es, qui est assez lent (si quelqu'un a r\u00e9ussi, n'h\u00e9sitez pas \u00e0 \u00e9crire dans les commentaires comment). Nous aurions pu dire aux analystes : \u00ab \u00c9coutez, apprenez Python et utilisez des r\u00e9pliques analytiques \u00bb, mais cela impliquerait une exigence suppl\u00e9mentaire en mati\u00e8re de recrutement, et il semblait pr\u00e9f\u00e9rable d'\u00e9viter cela si possible. Nous avons d\u00e9cid\u00e9 d'essayer la technologie FDW (Foreign Data Wrapper) : c'est essentiellement un dblink standard qui figure dans la norme SQL, mais avec une interface beaucoup plus conviviale. Sur cette base, nous avons cr\u00e9\u00e9 une solution qui a finalement \u00e9t\u00e9 adopt\u00e9e, et nous nous y sommes arr\u00eat\u00e9s. Les d\u00e9tails de cette solution seraient le sujet d'un article \u00e0 part enti\u00e8re, ou peut-\u00eatre m\u00eame de plusieurs, car il y a beaucoup \u00e0 dire : de la synchronisation des sch\u00e9mas des bases aux droits d'acc\u00e8s et \u00e0 l'anonymisation des donn\u00e9es personnelles. Il convient \u00e9galement de mentionner que cette solution ne remplace pas de v\u00e9ritables bases de donn\u00e9es analytiques et d'entrep\u00f4ts de donn\u00e9es ; elle ne r\u00e9sout qu'un probl\u00e8me sp\u00e9cifique.<\/p>\n<p>\u00c0 un niveau \u00e9lev\u00e9, cela se pr\u00e9sente comme suit :<\/p>\n<p><img decoding=\"async\" alt=\"Analyse op\u00e9rationnelle dans une architecture microservices : p\u0336o\u0336n\u0336y\u0336e\u0336t\u0336 \u0336e\u0336t\u0336 \u0336a\u0336i\u0336d\u0336e\u0336 des conseils pour Postgres FDW\" src=\"\/wp-content\/uploads\/2020\/04\/574da29dfdb40706afe9e817e789a61b.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIl y a une base de donn\u00e9es PostgreSQL o\u00f9 les utilisateurs peuvent stocker leurs donn\u00e9es de travail, et le plus important \u2014 cette base est connect\u00e9e via FDW aux r\u00e9pliques analytiques de tous les services. Cela permet d'\u00e9crire une requ\u00eate vers plusieurs bases, peu importe qu'il s'agisse de PostgreSQL, MySQL, MongoDB ou autre chose (un fichier, une API, si aucun wrapper appropri\u00e9 n'existe, vous pouvez \u00e9crire votre propre). Eh bien, \u00e7a a l'air bien, non ? On se s\u00e9pare ?<\/p>\n<p>Si tout se terminait aussi rapidement et simplement, cet article n'existerait probablement pas.<\/p>\n<p>Il est important de comprendre clairement comment Postgres traite les requ\u00eates vers des serveurs distants. Cela semble logique, mais souvent, cela est n\u00e9glig\u00e9 : Postgres divise la requ\u00eate en parties qui sont ex\u00e9cut\u00e9es sur les serveurs distants de mani\u00e8re ind\u00e9pendante, collecte ces donn\u00e9es, puis effectue les calculs finaux lui-m\u00eame. Par cons\u00e9quent, la vitesse d'ex\u00e9cution de la requ\u00eate d\u00e9pendra fortement de sa r\u00e9daction. Il convient \u00e9galement de noter que lorsque les donn\u00e9es proviennent d'un serveur distant, elles n'ont plus d'index, rien ne peut aider le planificateur ; par cons\u00e9quent, nous sommes les seuls capables de l'aider et de le guider. Et c'est pr\u00e9cis\u00e9ment ce dont j'aimerais parler plus en d\u00e9tail.<\/p>\n<h1>Requ\u00eate simple et plan associ\u00e9<\/h1>\n<p>\nPour illustrer comment PostgreSQL ex\u00e9cute une requ\u00eate sur une table de 6 millions de lignes \u00e0 distance <a class=\"wpil_keyword_link\" href=\"https:\/\/prohoster.info\/fr\/server\/dts-dronten\/\"   title=\"le serveur\" data-wpil-keyword-link=\"linked\"  data-wpil-monitor-id=\"2589\">le serveur<\/a>, examinons un plan simple.<\/p>\n<pre><code class=\"sql\">expliquer analyser en d\u00e9tail  \nSELECT count(1)\nFROM fdw_schema.table;\n\nAgr\u00e9gat  (co\u00fbt=418383.23..418383.24 lignes=1 largeur=8) (temps r\u00e9el=3857.198..3857.198 lignes=1 boucles=1)\n  Sortie : count(1)\n  -&gt;  Scan \u00c9tranger sur fdw_schema.&quot;table&quot;  (co\u00fbt=100.00..402376.14 lignes=6402838 largeur=0) (temps r\u00e9el=4.874..3256.511 lignes=6406868 boucles=1)\n        Sortie : &quot;table&quot;.id, &quot;table&quot;.is_active, &quot;table&quot;.meta, &quot;table&quot;.created_dt\n        SQL distant : SELECT NULL FROM fdw_schema.table\nTemps de planification : 0.986 ms\nTemps d'ex\u00e9cution : 3857.436 ms<\/code><\/pre>\n<p>\nL'utilisation de l'instruction VERBOSE permet de voir la requ\u00eate qui sera envoy\u00e9e au serveur distant et les r\u00e9sultats que nous recevrons pour un traitement ult\u00e9rieur (ligne RemoteSQL).<\/p>\n<p>Allons un peu plus loin et ajoutons quelques filtres \u00e0 notre requ\u00eate : un sur <b>boolean<\/b> le champ, un sur la pr\u00e9sence <b>timestamp<\/b> dans l'intervalle et un sur <b>jsonb<\/b>.<\/p>\n<pre><code class=\"sql\">expliquer analyser en d\u00e9tail\nSELECT count(1)\nFROM fdw_schema.table \nWHERE is_active is True\nAND created_dt BETWEEN CURRENT_DATE - INTERVAL '7 mois' \nAND CURRENT_DATE - INTERVAL '6 mois'\nAND meta-&gt;&gt;'source' = 'test';\n\nAgr\u00e9gat  (co\u00fbt=577487.69..577487.70 lignes=1 largeur=8) (temps r\u00e9el=27473.818..25473.819 lignes=1 boucles=1)\n  Sortie : count(1)\n  -&gt;  Scan \u00c9tranger sur fdw_schema.&quot;table&quot;  (co\u00fbt=100.00..577469.21 lignes=7390 largeur=0) (temps r\u00e9el=31.369..25372.466 lignes=1360025 boucles=1)\n        Sortie : &quot;table&quot;.id, &quot;table&quot;.is_active, &quot;table&quot;.meta, &quot;table&quot;.created_dt\n        Filtre : ((&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 mois'::interval)) AND (&quot;table&quot;.created_dt &lt;= ((('now'::cstring)::date)::timestamp avec fuseau horaire - '6 mois'::interval)))\n        Lignes supprim\u00e9es par le filtre : 5046843\n        SQL distant : SELECT created_dt, is_active, meta FROM fdw_schema.table\nTemps de planification : 0.665 ms\nTemps d'ex\u00e9cution : 27474.118 ms<\/code><\/pre>\n<p>\nC'est pr\u00e9cis\u00e9ment ici que se situe le point sur lequel il faut porter attention lors de l'\u00e9criture de requ\u00eates. Les filtres n'ont pas \u00e9t\u00e9 transmis au serveur distant, ce qui signifie que pour son ex\u00e9cution, PostgreSQL extrait les 6 millions de lignes pour ensuite les filtrer localement (ligne Filter) et effectuer l'agr\u00e9gation. La cl\u00e9 du succ\u00e8s est d'\u00e9crire la requ\u00eate de sorte que les filtres soient transf\u00e9r\u00e9s \u00e0 la machine distante, et que nous recevions et agr\u00e9gions uniquement les lignes n\u00e9cessaires. <\/p>\n<h1>C'est vraiment des b\u00eatises sur les bool\u00e9ens<\/h1>\n<p>\nAvec les champs boolean, tout est simple. Dans la requ\u00eate d'origine, le probl\u00e8me provenait de l'op\u00e9rateur <b>is<\/b>. Si nous le rempla\u00e7ons par <b>=<\/b>, nous obtiendrons le r\u00e9sultat suivant :<\/p>\n<pre><code class=\"sql\">expliquer analyser en d\u00e9tail\nSELECT count(1)\nFROM fdw_schema.table\nWHERE is_active = True\nAND created_dt BETWEEN CURRENT_DATE - INTERVAL '7 mois' \nAND CURRENT_DATE - INTERVAL '6 mois'\nAND meta-&gt;&gt;'source' = 'test';\n\nAgr\u00e9gat  (co\u00fbt=508010.14..508010.15 lignes=1 largeur=8) (temps r\u00e9el=19064.314..19064.314 lignes=1 boucles=1)\n  Sortie : count(1)\n  -&gt;  Scan \u00c9tranger sur fdw_schema.&quot;table&quot;  (co\u00fbt=100.00..507988.44 lignes=8679 largeur=0) (temps r\u00e9el=33.035..18951.278 lignes=1360025 boucles=1)\n        Sortie : &quot;table&quot;.id, &quot;table&quot;.is_active, &quot;table&quot;.meta, &quot;table&quot;.created_dt\n        Filtre : (((&quot;table&quot;.meta -&gt;&gt; 'source'::text) = 'test'::text) AND (&quot;table&quot;.created_dt &gt;= (('now'::cstring)::date - '7 mois'::interval)) AND (&quot;table&quot;.created_dt &lt;= ((('now'::cstring)::date)::timestamp avec fuseau horaire - '6 mois'::interval)))\n        Lignes supprim\u00e9es par le filtre : 3567989\n        SQL distant : SELECT created_dt, meta FROM fdw_schema.table WHERE (is_active)\nTemps de planification : 0.834 ms\nTemps d'ex\u00e9cution : 19064.534 ms<\/code><\/pre>\n<p>\nComme vous pouvez le voir, le filtre a \u00e9t\u00e9 envoy\u00e9 sur le serveur distant, et le temps d'ex\u00e9cution a \u00e9t\u00e9 r\u00e9duit de 27 \u00e0 19 secondes. <\/p>\n<p>Il convient de noter que l'op\u00e9rateur <b>is<\/b> diff\u00e8re de l'op\u00e9rateur <b>=<\/b> en ce sens qu'il peut travailler avec la valeur Null. Cela signifie que <b>is not True<\/b> dans le filtre conservera les valeurs False et Null, tandis que <b>!= True<\/b> ne conservera que les valeurs False. Par cons\u00e9quent, lors du remplacement de l'op\u00e9rateur <b>is not<\/b> il convient de transmettre au filtre deux conditions avec l'op\u00e9rateur OR, par exemple, <b>WHERE (col != True) OR (col is null)<\/b>.<\/p>\n<p>Nous avons compris le boolean, passons \u00e0 autre chose. Mais d'abord, revenons au filtre de valeur bool\u00e9enne dans son \u00e9tat original pour examiner ind\u00e9pendamment l'effet des autres changements.<\/p>\n<h1>timestamptz? hz<\/h1>\n<p>\nEn fait, il arrive souvent que l'on doive exp\u00e9rimenter sur la fa\u00e7on de r\u00e9diger correctement une requ\u00eate impliquant des serveurs distants, puis chercher une explication de pourquoi cela se passe ainsi. Il y a tr\u00e8s peu d'informations \u00e0 ce sujet disponibles sur Internet. Par exemple, dans nos exp\u00e9riences, nous avons constat\u00e9 que le filtre sur une date fixe fonctionne parfaitement sur le serveur distant, mais lorsque nous souhaitons d\u00e9finir la date dynamiquement, par exemple avec now() ou CURRENT_DATE, cela ne fonctionne pas. Dans notre exemple, nous avons ajout\u00e9 un filtre pour que la colonne created_at contienne des donn\u00e9es sp\u00e9cifiquement d'un mois en arri\u00e8re (BETWEEN CURRENT_DATE \u2014 INTERVAL &#8216;7 mois&#8217; AND CURRENT_DATE \u2014 INTERVAL &#8216;6 mois&#8217;). Que devrions-nous faire dans ce cas ?<\/p>\n<pre><code class=\"sql\">expliquer analyser d\u00e9taill\u00e9\nSELECT count(1)\nFROM fdw_schema.table \nWHERE is_active is True\nET created_dt &gt;= (SELECT CURRENT_DATE::timestamptz - INTERVAL '7 mois') \nET created_dt &gt;'source' = 'test';\n\nAgr\u00e9gation (co\u00fbt=306875.17..306875.18 lignes=1 largeur=8) (temps r\u00e9el=4789.114..4789.115 lignes=1 boucles=1)\n  Sortie : count(1)\n  InitPlan 1 (retourne $0)\n    -&gt; R\u00e9sultat (co\u00fbt=0.00..0.02 lignes=1 largeur=8) (temps r\u00e9el=0.007..0.008 lignes=1 boucles=1)\n          Sortie : ((('now'::cstring)::date)::timestamp with time zone - '7 mois'::interval)\n  InitPlan 2 (retourne $1)\n    -&gt; R\u00e9sultat (co\u00fbt=0.00..0.02 lignes=1 largeur=8) (temps r\u00e9el=0.002..0.002 lignes=1 boucles=1)\n          Sortie : ((('now'::cstring)::date)::timestamp with time zone - '6 mois'::interval)\n  -&gt; Scan \u00c9tranger sur fdw_schema.\"table\"  (co\u00fbt=100.02..306874.86 lignes=105 largeur=0) (temps r\u00e9el=23.475..4681.419 lignes=1360025 boucles=1)\n        Sortie : \"table\".id, \"table\".is_active, \"table\".meta, \"table\".created_dt\n        Filtre : ((\"table\".is_active IS TRUE) ET ((\"table\".meta -&gt;&gt; 'source'::text) = 'test'::text))\n        Lignes supprim\u00e9es par le filtre : 76934\n        SQL distant : SELECT is_active, meta FROM fdw_schema.table WHERE ((created_dt &gt;= $1::timestamp with time zone)) ET ((created_dt &lt; $2::timestamp with time zone))\nTemps de planification : 0.703 ms\nTemps d&#039;ex\u00e9cution : 4789.379 ms<\/code><\/pre>\n<p>\nNous avons sugg\u00e9r\u00e9 au planificateur de calculer \u00e0 l'avance la date dans la sous-requ\u00eate et de d\u00e9j\u00e0 transmettre la variable pr\u00eate dans le filtre. Et ce conseil nous a donn\u00e9 un excellent r\u00e9sultat, la requ\u00eate est devenue presque six fois plus rapide !<\/p>\n<p>Encore une fois, il est important d'\u00eatre attentif : le type de donn\u00e9es dans la sous-requ\u00eate doit correspondre \u00e0 celui du champ sur lequel nous filtrons, sinon le planificateur d\u00e9cidera que les types \u00e9tant diff\u00e9rents, il faut d'abord r\u00e9cup\u00e9rer toutes les donn\u00e9es puis filtrer localement.<\/p>\n<p>Ramenons le filtre par date \u00e0 sa valeur initiale.<\/p>\n<h1>Freddy vs. Jsonb<\/h1>\n<p>\nEn fait, les champs bool\u00e9ens et les dates ont d\u00e9j\u00e0 suffisamment acc\u00e9l\u00e9r\u00e9 notre requ\u00eate, cependant, il restait encore un type de donn\u00e9es. La bataille pour le filtrage sur celui-ci, honn\u00eatement, n'est pas encore termin\u00e9e, bien qu'il y ait eu des succ\u00e8s ici aussi. Alors, voici comment nous avons r\u00e9ussi \u00e0 faire passer le filtre par <b>jsonb<\/b> le champ vers le serveur distant.<\/p>\n<pre><code class=\"sql\">expliquer analyser d\u00e9taill\u00e9\nSELECT count(1)\nFROM fdw_schema.table \nWHERE is_active is True\nET created_dt BETWEEN CURRENT_DATE - INTERVAL '7 mois' \nET CURRENT_DATE - INTERVAL '6 mois'\nET meta @&gt; '{\"source\":\"test\"}'::jsonb;\n\nAgr\u00e9gation (co\u00fbt=245463.60..245463.61 lignes=1 largeur=8) (temps r\u00e9el=6727.589..6727.590 lignes=1 boucles=1)\n  Sortie : count(1)\n  -&gt; Scan \u00c9tranger sur fdw_schema.\"table\"  (co\u00fbt=1100.00..245459.90 lignes=1478 largeur=0) (temps r\u00e9el=16.213..6634.794 lignes=1360025 boucles=1)\n        Sortie : \"table\".id, \"table\".is_active, \"table\".meta, \"table\".created_dt\n        Filtre : ((\"table\".is_active IS TRUE) ET (\"table\".created_dt &gt;= (('now'::cstring)::date - '7 mois'::interval)) ET (\"table\".created_dt  '{\"source\": \"test\"}'::jsonb))\nTemps de planification : 0.747 ms\nTemps d'ex\u00e9cution : 6727.815 ms<\/code><\/pre>\n<p>\nAu lieu des op\u00e9rateurs de filtrage, il est n\u00e9cessaire d'utiliser l'op\u00e9rateur de pr\u00e9sence d'un <b>jsonb<\/b> dans l'autre. 7 secondes au lieu des 29 initiales. Pour l'instant, c'est la seule option r\u00e9ussie pour le transfert des filtres par <b>jsonb<\/b> vers un serveur distant, mais il est important de prendre en compte une contrainte : nous utilisons la version 9.6 de la base, cependant nous pr\u00e9voyons de terminer les derniers tests et de passer \u00e0 la version 12 d'ici la fin avril. Une fois que nous serons \u00e0 jour, nous vous informerons sur l'impact, car il y a de nombreux changements sur lesquels nous avons beaucoup d'espoirs : json_path, nouveau comportement CTE, push down (pr\u00e9sent depuis la version 10). Nous avons h\u00e2te d'essayer cela.<\/p>\n<h1>Finish him<\/h1>\n<p>\nNous avons v\u00e9rifi\u00e9 comment chaque changement affecte la vitesse de la requ\u00eate individuellement. Voyons maintenant ce qui se passe lorsque les trois filtres sont correctement \u00e9crits.<\/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>\nOui, la requ\u00eate semble plus complexe, c'est un co\u00fbt forc\u00e9, mais le temps d'ex\u00e9cution est de 2 secondes, ce qui est plus de 10 fois plus rapide ! Et nous parlons ici d'une simple requ\u00eate sur un ensemble de donn\u00e9es relativement petit. Sur des requ\u00eates r\u00e9elles, nous avons obtenu des gains allant jusqu'\u00e0 plusieurs centaines de fois.<\/p>\n<p>En r\u00e9sum\u00e9 : si vous utilisez PostgreSQL avec FDW, v\u00e9rifiez toujours si tous les filtres sont envoy\u00e9s sur le serveur distant, et vous serez heureux... Du moins jusqu'\u00e0 ce que vous rencontriez des jointures entre des tables venant de diff\u00e9rentes <a class=\"wpil_keyword_link\" href=\"https:\/\/prohoster.info\/fr\/server\/\"   title=\"serveurs\" data-wpil-keyword-link=\"linked\"  data-wpil-monitor-id=\"1482\">serveurs<\/a>. Mais c'est d\u00e9j\u00e0 l'histoire d'un autre article.<\/p>\n<p>Merci de votre attention ! Je serais heureux de lire vos questions, commentaires, ainsi que des histoires sur votre exp\u00e9rience dans les commentaires.<br \/>\n<br \/>Source : <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 5.0.2 - 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.\" \/>\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\/fr\/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) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"fr_FR\" \/>\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.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/fr\/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\udd47Analyse op\u00e9rationnelle dans une architecture microservices : comprendre et expliquer Postgres FDW | ProHoster","description":"L'architecture microservices, comme tout dans ce monde, a ses avantages et ses inconv\u00e9nients. Certains processus deviennent plus simples avec elle, d'autres \u2014 plus compliqu\u00e9s.","canonical_url":"https:\/\/prohoster.info\/fr\/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":"fr_FR","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.","og:url":"https:\/\/prohoster.info\/fr\/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","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/79467","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/comments?post=79467"}],"version-history":[{"count":2,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/79467\/revisions"}],"predecessor-version":[{"id":159871,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/79467\/revisions\/159871"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media\/79468"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media?parent=79467"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/categories?post=79467"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/tags?post=79467"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}