{"id":30900,"date":"2019-10-31T21:38:02","date_gmt":"2019-10-31T18:38:02","guid":{"rendered":"https:\/\/prohoster.info\/blog\/parallelnye-zaprosy-v-postgresql\/"},"modified":"2019-10-31T21:38:02","modified_gmt":"2019-10-31T18:38:02","slug":"parallelnye-zaprosy-v-postgresql","status":"publish","type":"post","link":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","title":{"rendered":"Requ\u00eates parall\u00e8les dans PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Requ\u00eates parall\u00e8les dans PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/04\/bbb4b4d3f8714bbdb9b26ada2f2253b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLes processeurs modernes ont de nombreux c\u0153urs. Pendant des ann\u00e9es, les applications ont envoy\u00e9 des requ\u00eates aux bases de donn\u00e9es en parall\u00e8le. Si c'est une requ\u00eate de rapport sur de nombreuses lignes dans une table, elle s'ex\u00e9cute plus rapidement lorsqu'elle utilise plusieurs c\u0153urs, et c'est possible dans PostgreSQL \u00e0 partir de la version 9.6.<\/p>\n<p><\/p>\n<p>Il a fallu 3 ans pour mettre en \u0153uvre la fonction de requ\u00eates parall\u00e8les : il a fallu r\u00e9\u00e9crire le code \u00e0 diff\u00e9rentes \u00e9tapes de l'ex\u00e9cution des requ\u00eates. PostgreSQL 9.6 a introduit l'infrastructure pour am\u00e9liorer davantage le code. Dans les versions suivantes, d'autres types de requ\u00eates sont \u00e9galement ex\u00e9cut\u00e9s en parall\u00e8le.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3 id=\"ogranicheniya\">Restrictions<\/h3>\n<p><\/p>\n<ul>\n<li>N'activez pas l'ex\u00e9cution parall\u00e8le si tous les c\u0153urs sont d\u00e9j\u00e0 occup\u00e9s, sinon d'autres requ\u00eates seront ralenties.<\/li>\n<li>Surtout, le traitement parall\u00e8le avec des valeurs WORK_MEM \u00e9lev\u00e9es utilise beaucoup de m\u00e9moire : chaque jointure de hachage ou chaque tri n\u00e9cessite de la m\u00e9moire \u00e9quivalente \u00e0 work_mem.<\/li>\n<li>Les requ\u00eates OLTP \u00e0 faible latence ne peuvent pas \u00eatre acc\u00e9l\u00e9r\u00e9es par l'ex\u00e9cution parall\u00e8le. Et si une requ\u00eate retourne une seule ligne, le traitement parall\u00e8le ne fait que la ralentir.<\/li>\n<li>Les d\u00e9veloppeurs aiment utiliser le benchmark TPC-H. Peut-\u00eatre avez-vous des requ\u00eates similaires pour un ex\u00e9cution parall\u00e8le optimale.<\/li>\n<li>Seules les requ\u00eates SELECT sans verrouillage pr\u00e9dictif s'ex\u00e9cutent en parall\u00e8le.<\/li>\n<li>Parfois, un bon indexage est pr\u00e9f\u00e9rable \u00e0 un scan s\u00e9quentiel en mode parall\u00e8le sur la table.<\/li>\n<li>Les suspensions de requ\u00eates et les curseurs ne sont pas pris en charge.<\/li>\n<li>Les fonctions de fen\u00eatre et les fonctions d'agr\u00e9gation sur des ensembles ordonn\u00e9s ne sont pas parall\u00e8les.<\/li>\n<li>Vous ne gagnez rien dans les charges de travail d'entr\u00e9e-sortie.<\/li>\n<li>Il n'existe pas d'algorithmes de tri parall\u00e8les. Mais les requ\u00eates avec tris peuvent \u00eatre ex\u00e9cut\u00e9es en parall\u00e8le sous certains aspects.<\/li>\n<li>Remplacez CTE (WITH \u2026) par un SELECT imbriqu\u00e9 pour inclure le traitement parall\u00e8le.<\/li>\n<li>Les wrappers de donn\u00e9es tierces ne prennent pas encore en charge le traitement parall\u00e8le (mais pourraient le faire !)<\/li>\n<li>FULL OUTER JOIN n'est pas pris en charge.<\/li>\n<li>max_rows d\u00e9sactive le traitement parall\u00e8le.<\/li>\n<li>Si une fonction dans la requ\u00eate n'est pas marqu\u00e9e comme PARALLEL SAFE, elle sera ex\u00e9cut\u00e9e en mode mono-fil.<\/li>\n<li>Le niveau d'isolation de transaction SERIALIZABLE d\u00e9sactive le traitement parall\u00e8le.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"testovaya-sreda\">Environnement de test<\/h3>\n<p><\/p>\n<p>Les d\u00e9veloppeurs de PostgreSQL ont essay\u00e9 de r\u00e9duire le temps de r\u00e9ponse des requ\u00eates du benchmark TPC-H. T\u00e9l\u00e9chargez le benchmark et <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">adaptez-le \u00e0 PostgreSQL<\/a><\/noindex>Ceci n'est pas une utilisation officielle du benchmark TPC-H - pas pour comparer des bases de donn\u00e9es ou du mat\u00e9riel.<\/p>\n<p><\/p>\n<ol>\n<li>T\u00e9l\u00e9chargez TPC-H_Tools_v2.17.3.zip (ou une version plus r\u00e9cente) <noindex><a rel=\"nofollow\" href=\"http:\/\/www.tpc.org\/tpc_documents_current_versions\/current_specifications.asp\">sur le site TPC<\/a><\/noindex>.<\/li>\n<li>Renommez makefile.suite en Makefile et modifiez comme d\u00e9crit ici : <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">https:\/\/github.com\/tvondra\/pg_tpch <\/a><\/noindex>Compilez le code avec la commande make.<\/li>\n<li>G\u00e9n\u00e9rez des donn\u00e9es : <code>.\/dbgen -s 10<\/code> cr\u00e9e une base de donn\u00e9es de 23 Go. Cela suffira pour voir la diff\u00e9rence de performance entre les requ\u00eates parall\u00e8les et non parall\u00e8les.<\/li>\n<li>Convertissez les fichiers <code>tbl<\/code> dans <code>csv avec for<\/code> et <code>sed<\/code>.<\/li>\n<li>Clonez le r\u00e9f\u00e9rentiel <code>pg_tpch<\/code> et copiez les fichiers <code>csv<\/code> dans <code>pg_tpch\/dss\/data<\/code>.<\/li>\n<li>Cr\u00e9ez des requ\u00eates avec la commande <code>qgen<\/code>.<\/li>\n<li>Chargez les donn\u00e9es dans la base avec la commande <code>.\/tpch.sh<\/code>.<\/li>\n<\/ol>\n<p><\/p>\n<h3 id=\"parallelnoe-posledovatelnoe-skanirovanie\">Scan s\u00e9quentiel parall\u00e8le<\/h3>\n<p><\/p>\n<p>Cela peut \u00eatre plus rapide non pas \u00e0 cause de la lecture parall\u00e8le, mais parce que les donn\u00e9es sont dispers\u00e9es sur plusieurs c\u0153urs de CPU. Dans les syst\u00e8mes d'exploitation modernes, les fichiers de donn\u00e9es PostgreSQL sont bien mis en cache. Avec la lecture anticipative, il est possible de r\u00e9cup\u00e9rer de l'entrep\u00f4t un bloc plus grand que celui demand\u00e9 par le d\u00e9mon PG. Par cons\u00e9quent, la performance de la requ\u00eate n'est pas limit\u00e9e par les entr\u00e9es-sorties du disque. Elle utilise des cycles CPU pour :<\/p>\n<p><\/p>\n<ul>\n<li>lire les lignes une par une \u00e0 partir des pages de la table ;<\/li>\n<li>comparer les valeurs des lignes et les conditions <code>O\u00d9<\/code>.<\/li>\n<\/ul>\n<p><\/p>\n<p>Effectuons une requ\u00eate simple <code>select<\/code>:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">tpch=# explain analyze select l_quantity as sum_qty from lineitem where l_shipdate &lt;= date &#039;1998-12-01&#039; - interval &#039;105&#039; day;\nPLAN DE LA REQU\u00caTE\n--------------------------------------------------------------------------------------------------------------------------\nScan S\u00e9quentiel sur lineitem (co\u00fbt=0.00..1964772.00 lignes=58856235 largeur=5) (temps r\u00e9el=0.014..16951.669 lignes=58839715 boucles=1)\nFiltre : (l_shipdate &lt;= &#039;1998-08-18 00:00:00&#039;::timestamp without time zone)\nLignes supprim\u00e9es par le filtre : 1146337\nTemps de planification : 0.203 ms\nTemps d&#039;ex\u00e9cution : 19035.100 ms<\/code><\/pre>\n<p><\/p>\n<p>Le scan s\u00e9quentiel donne trop de lignes sans agr\u00e9gation, si bien que la requ\u00eate s'ex\u00e9cute sur un seul c\u0153ur de CPU.<\/p>\n<p><\/p>\n<p>Si l'on ajoute <code>SUM()<\/code>, on voit que deux processus de travail peuvent aider \u00e0 acc\u00e9l\u00e9rer la requ\u00eate :<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">explain analyze select sum(l_quantity) as sum_qty from lineitem where l_shipdate  Rassembler (co\u00fbt=1589701.91..1589702.12 lignes=2 largeur=32) (temps r\u00e9el=8553.241..8555.067 lignes=3 boucles=1)\nTravailleurs pr\u00e9vus : 2\nTravailleurs lanc\u00e9s : 2\n-&gt; Agr\u00e9gation partielle (co\u00fbt=1588701.91..1588701.92 lignes=1 largeur=32) (temps r\u00e9el=8547.546..8547.546 lignes=1 boucles=3)\n-&gt; Scan s\u00e9quentiel parall\u00e8le sur lineitem (co\u00fbt=0.00..1527393.33 lignes=24523431 largeur=5) (temps r\u00e9el=0.038..5998.417 lignes=19613238 boucles=3)\nFiltre : (l_shipdate &lt;= &#039;1998-08-18 00:00:00&#039;::timestamp without time zone)\nLignes supprim\u00e9es par le filtre : 382112\nTemps de planification : 0.241 ms\nTemps d&#039;ex\u00e9cution : 8555.131 ms<\/code><\/pre>\n<p><\/p>\n<h3 id=\"parallelnaya-agregaciya\">Agr\u00e9gation parall\u00e8le<\/h3>\n<p><\/p>\n<p>Le n\u0153ud \u00ab\u00a0Scan s\u00e9quentiel parall\u00e8le\u00a0\u00bb g\u00e9n\u00e8re des lignes pour l'agr\u00e9gation partielle. Le n\u0153ud \u00ab\u00a0Agr\u00e9gation partielle\u00a0\u00bb r\u00e9duit ces lignes avec <code>SUM()<\/code>. \u00c0 la fin, le compteur SUM de chaque processus de travail est rassembl\u00e9 par le n\u0153ud \u00ab\u00a0Gather\u00a0\u00bb.<\/p>\n<p><\/p>\n<p>Le r\u00e9sultat final est calcul\u00e9 par le n\u0153ud \u00ab\u00a0Finalize Aggregate\u00a0\u00bb. Si vous avez vos propres fonctions d'agr\u00e9gation, n'oubliez pas de les marquer comme \u00ab\u00a0parallel safe\u00a0\u00bb.<\/p>\n<p><\/p>\n<h3 id=\"kolichestvo-rabochih-processov\">Nombre de processus de travail<\/h3>\n<p><\/p>\n<p>Le nombre de processus de travail peut \u00eatre augment\u00e9 sans red\u00e9marrer le serveur :<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">explain analyze select sum(l_quantity) as sum_qty from lineitem where l_shipdate  Rassembler (co\u00fbt=1589701.91..1589702.12 lignes=2 largeur=32) (temps r\u00e9el=8553.241..8555.067 lignes=3 boucles=1)\nTravailleurs pr\u00e9vus : 2\nTravailleurs lanc\u00e9s : 2\n-&gt; Agr\u00e9gation partielle (co\u00fbt=1588701.91..1588701.92 lignes=1 largeur=32) (temps r\u00e9el=8547.546..8547.546 lignes=1 boucles=3)\n-&gt; Scan s\u00e9quentiel parall\u00e8le sur lineitem (co\u00fbt=0.00..1527393.33 lignes=24523431 largeur=5) (temps r\u00e9el=0.038..5998.417 lignes=19613238 boucles=3)\nFiltre : (l_shipdate &lt;= &#039;1998-08-18 00:00:00&#039;::timestamp without time zone)\nLignes supprim\u00e9es par le filtre : 382112\nTemps de planification : 0.241 ms\nTemps d&#039;ex\u00e9cution : 8555.131 ms<\/code><\/pre>\n<p><\/p>\n<p>Que se passe-t-il ici ? Le nombre de processus de travail a doubl\u00e9, et la requ\u00eate est devenue seulement 1,6599 fois plus rapide. Les calculs sont int\u00e9ressants. Nous avions 2 processus de travail et 1 leader. Apr\u00e8s modification, il y en a 4+1.<\/p>\n<p><\/p>\n<p>Notre maximum d'acc\u00e9l\u00e9ration gr\u00e2ce au traitement en parall\u00e8le : 5\/3 = 1,66(6) fois.<\/p>\n<p><\/p>\n<h2 id=\"kak-eto-rabotaet\">Comment cela fonctionne ?<\/h2>\n<p><\/p>\n<h3 id=\"processy\">Processus<\/h3>\n<p><\/p>\n<p>L'ex\u00e9cution de la requ\u00eate commence toujours par le processus leader. Le leader effectue tout le travail non parall\u00e8le et une partie du traitement parall\u00e8le. Les autres processus, effectuant les m\u00eames requ\u00eates, sont appel\u00e9s processus de travail. Le traitement parall\u00e8le utilise l'infrastructure <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/bgworker.html\">des processus de travail en arri\u00e8re-plan dynamiques<\/a><\/noindex> (\u00e0 partir de la version 9.4). Comme d'autres parties de PostgreSQL utilisent des processus plut\u00f4t que des threads, une requ\u00eate avec 3 processus de travail pouvait \u00eatre 4 fois plus rapide que le traitement traditionnel.<\/p>\n<p><\/p>\n<h3 id=\"vzaimodeystvie\">Interaction<\/h3>\n<p><\/p>\n<p>Les processus de travail communiquent avec le leader via une file d'attente de messages (bas\u00e9e sur la m\u00e9moire partag\u00e9e). Chaque processus a 2 files d'attente : pour les erreurs et pour les tuples.<\/p>\n<p><\/p>\n<h3 id=\"skolko-nuzhno-rabochih-processov\">Combien de processus de travail sont n\u00e9cessaires ?<\/h3>\n<p><\/p>\n<p>La limite minimale est d\u00e9finie par le param\u00e8tre <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/runtime-config-resource.html#GUC-MAX-PARALLEL-WORKERS-PER-GATHER\"><code>max_parallel_workers_per_gather<\/code><\/a><\/noindex>. Ensuite, l'ex\u00e9cuteur de requ\u00eates prend des processus de travail \u00e0 partir d'un pool, limit\u00e9 par le param\u00e8tre <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/runtime-config-resource.html#GUC-MAX-WORKER-PROCESSES\"><code>max_parallel_workers size<\/code><\/a><\/noindex>. La derni\u00e8re limite est <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/runtime-config-resource.html#GUC-MAX-WORKER-PROCESSES\"><code>max_worker_processes<\/code><\/a><\/noindex>, c'est-\u00e0-dire le nombre total de processus de fond.<\/p>\n<p><\/p>\n<p>Si un processus de travail ne peut pas \u00eatre allou\u00e9, le traitement sera uniprocessus.<\/p>\n<p><\/p>\n<p>Le planificateur de requ\u00eates peut r\u00e9duire le nombre de processus de travail en fonction de la taille de la table ou de l'index. Pour cela, il y a des param\u00e8tres <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/runtime-config-query.html#GUC-MIN-PARALLEL-TABLE-SCAN-SIZE\"><code>min_parallel_table_scan_size<\/code><\/a><\/noindex> et <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/runtime-config-query.html#GUC-MIN-PARALLEL-INDEX-SCAN-SIZE\"><code>min_parallel_index_scan_size<\/code><\/a><\/noindex>.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">set min_parallel_table_scan_size='8MB'\n8MB table =&gt; 1 worker\n24MB table =&gt; 2 workers\n72MB table =&gt; 3 workers\nx =&gt; log(x \/ min_parallel_table_scan_size) \/ log(3) + 1 worker<\/code><\/pre>\n<p><\/p>\n<p>Chaque fois que la table est 3 fois plus grande que <code>min_parallel_(index|table)_scan_size<\/code>, Postgres ajoute un processus de travail. Le nombre de processus de travail n'est pas bas\u00e9 sur les co\u00fbts. La d\u00e9pendance circulaire complique les impl\u00e9mentations complexes. Au lieu de cela, le planificateur utilise des r\u00e8gles simples.<\/p>\n<p><\/p>\n<p>En pratique, ces r\u00e8gles ne s'appliquent pas toujours \u00e0 la production, il est donc possible de modifier le nombre de processus de travail pour une table sp\u00e9cifique : ALTER TABLE \u2026 SET (<code>parallel_workers = N<\/code>).<\/p>\n<p><\/p>\n<h3 id=\"pochemu-parallelnaya-obrabotka-ne-ispolzuetsya\">Pourquoi le traitement parall\u00e8le n'est-il pas utilis\u00e9 ?<\/h3>\n<p><\/p>\n<p>En plus de la longue liste de limitations, il y a aussi des v\u00e9rifications de co\u00fbt :<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/runtime-config-query.html#GUC-PARALLEL-SETUP-COST\"><code>parallel_setup_cost<\/code><\/a><\/noindex> \u2014 pour \u00e9viter le traitement parall\u00e8le des requ\u00eates courtes. Ce param\u00e8tre \u00e9value le temps n\u00e9cessaire \u00e0 la pr\u00e9paration de la m\u00e9moire, au lancement du processus et \u00e0 l'\u00e9change initial de donn\u00e9es.<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/runtime-config-query.html#GUC-PARALLEL-TUPLE-COST\"><code>parallel_tuple_cost<\/code><\/a><\/noindex>: la communication entre le leader et les travailleurs peut prendre plus de temps proportionnellement au nombre de tuples des processus de travail. Ce param\u00e8tre calcule les co\u00fbts d'\u00e9change de donn\u00e9es.<\/p>\n<p><\/p>\n<h3 id=\"soedineniya-vlozhennyh-ciklov--nested-loop-join\">Jointures en boucle imbriqu\u00e9es \u2014 Nested Loop Join<\/h3>\n<p><\/p>\n<pre><code class=\"plaintext\">PostgreSQL 9.6+ peut ex\u00e9cuter des boucles imbriqu\u00e9es en parall\u00e8le \u2014 c'est une op\u00e9ration simple.\n\nexplain (costs off) select c_custkey, count(o_orderkey)\n from customer left outer join orders on\n c_custkey = o_custkey and o_comment not like '%specialposits%'\n group by c_custkey;\n PLAN DE REQU\u00caTE\n--------------------------------------------------------------------------------------\n Finalize GroupAggregate\n Cl\u00e9 de groupe : customer.c_custkey\n -&gt; Gather Merge\n Travailleurs pr\u00e9vus : 4\n -&gt; Partial GroupAggregate\n Cl\u00e9 de groupe : customer.c_custkey\n -&gt; Jointure gauche imbriqu\u00e9e\n -&gt; Scan d'index parall\u00e8le uniquement en utilisant customer_pkey sur customer\n -&gt; Scan d'index en utilisant idx_orders_custkey sur orders\n Condition d'index : (customer.c_custkey = o_custkey)\n Filtrer : ((o_comment)::text !~~ '%specialposits%'::text)<\/code><\/pre>\n<p><\/p>\n<p>La collecte se fait \u00e0 la derni\u00e8re \u00e9tape, donc la jointure en boucle imbriqu\u00e9e \u2014 Nested Loop Left Join \u2014 est une op\u00e9ration parall\u00e8le. Le Parallel Index Only Scan n'est apparu qu'\u00e0 partir de la version 10. Il fonctionne de mani\u00e8re similaire \u00e0 un scan s\u00e9quentiel parall\u00e8le. La condition <code>c_custkey = o_custkey<\/code> lit un ordre pour chaque ligne client. Donc, ce n'est pas parall\u00e8le.<\/p>\n<p><\/p>\n<h3 id=\"hesh-soedinenie--hash-join\">Jointure par hachage \u2014 Hash Join<\/h3>\n<p><\/p>\n<p>Chaque processus de travail cr\u00e9e sa propre table de hachage jusqu'\u00e0 PostgreSQL 11. Et si le nombre de ces processus d\u00e9passe quatre, la performance ne s'am\u00e9liorera pas. Dans la nouvelle version, la table de hachage est partag\u00e9e. Chaque processus de travail peut utiliser WORK_MEM pour cr\u00e9er une table de hachage.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">s\u00e9lectionner\n        l_shipmode,\n        somme(cas\n                quand o_orderpriority = '1-URGENT'\n                        ou o_orderpriority = '2-HIGH'\n                        alors 1\n                sinon 0\n        fin) comme high_line_count,\n        somme(cas\n                quand o_orderpriority &lt;&gt; '1-URGENT'\n                        et o_orderpriority &lt;&gt; '2-HIGH'\n                        alors 1\n                sinon 0\n        fin) comme low_line_count\n\u00e0 partir de\n        commandes,\n        lignearticle\no\u00f9\n        o_orderkey = l_orderkey\n        et l_shipmode dans ('MAIL', 'AIR')\n        et l_commitdate &lt; l_receiptdate\n        et l_shipdate &lt; l_commitdate\n        et l_receiptdate &gt;= date '1996-01-01'\n        et l_receiptdate &lt; date '1996-01-01' + intervalle '1' an\ngrouper par\n        l_shipmode\nordre par\n        l_shipmode\nLIMIT 1;\n                                                                                                                                    PLAN DE CONSULTATION\n-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n Limite  (co\u00fbt=1964755.66..1964961.44 lignes=1 largeur=27) (temps r\u00e9el=7579.592..7922.997 lignes=1 boucles=1)\n   -&gt;  Finaliser GroupAggregate  (co\u00fbt=1964755.66..1966196.11 lignes=7 largeur=27) (temps r\u00e9el=7579.590..7579.591 lignes=1 boucles=1)\n         Cl\u00e9 de groupe: lignearticle.l_shipmode\n         -&gt;  Rassembler Fusionner  (co\u00fbt=1964755.66..1966195.83 lignes=28 largeur=27) (temps r\u00e9el=7559.593..7922.319 lignes=6 boucles=1)\n               Travailleurs pr\u00e9vus: 4\n               Travailleurs lanc\u00e9s: 4\n               -&gt;  GroupAggregate partiel  (co\u00fbt=1963755.61..1965192.44 lignes=7 largeur=27) (temps r\u00e9el=7548.103..7564.592 lignes=2 boucles=5)\n                     Cl\u00e9 de groupe: lignearticle.l_shipmode\n                     -&gt;  Trier  (co\u00fbt=1963755.61..1963935.20 lignes=71838 largeur=27) (temps r\u00e9el=7530.280..7539.688 lignes=62519 boucles=5)\n                           Cl\u00e9 de tri: lignearticle.l_shipmode\n                           M\u00e9thode de tri: fusion externe  Disque: 2304kB\n                           Ouvrier 0:  M\u00e9thode de tri: fusion externe  Disque: 2064kB\n                           Ouvrier 1:  M\u00e9thode de tri: fusion externe  Disque: 2384kB\n                           Ouvrier 2:  M\u00e9thode de tri: fusion externe  Disque: 2264kB\n                           Ouvrier 3:  M\u00e9thode de tri: fusion externe  Disque: 2336kB\n                           -&gt;  Jointure de hachage parall\u00e8le  (co\u00fbt=382571.01..1957960.99 lignes=71838 largeur=27) (temps r\u00e9el=7036.917..7499.692 lignes=62519 boucles=5)\n                                 Condition de hachage: (lignearticle.l_orderkey = commandes.o_orderkey)\n                                 -&gt;  Analyse s\u00e9quentielle parall\u00e8le sur lignearticle  (co\u00fbt=0.00..1552386.40 lignes=71838 largeur=19) (temps r\u00e9el=0.583..4901.063 lignes=62519 boucles=5)\n                                       Filtre: ((l_shipmode = TOUT ('{MAIL,AIR}'::bpchar[])) ET (l_commitdate &lt; l_receiptdate) ET (l_shipdate &lt; l_commitdate) ET (l_receiptdate &gt;= '1996-01-01'::date) ET (l_receiptdate &lt; '1997-01-01 00:00:00'::timestamp sans fuseau horaire))\n                                       Lignes supprim\u00e9es par le filtre: 11934691\n                                 -&gt;  Hachage parall\u00e8le  (co\u00fbt=313722.45..313722.45 lignes=3750045 largeur=20) (temps r\u00e9el=2011.518..2011.518 lignes=3000000 boucles=5)\n                                       Seaux: 65536  Lots: 256  Utilisation de la m\u00e9moire: 3840kB\n                                       -&gt;  Analyse s\u00e9quentielle parall\u00e8le sur commandes  (co\u00fbt=0.00..313722.45 lignes=3750045 largeur=20) (temps r\u00e9el=0.029..995.948 lignes=3000000 boucles=5)\n Temps de planification: 0.977 ms\n Temps d'ex\u00e9cution: 7923.770 ms<\/code><\/pre>\n<p><\/p>\n<p>La requ\u00eate 12 de TPC-H montre clairement une jointure de hachage parall\u00e8le. Chaque processus de travail participe \u00e0 la cr\u00e9ation d'une table de hachage commune.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-sliyaniem--merge-join\">Joint de fusion \u2014 Merge Join<\/h3>\n<p><\/p>\n<p>Le joint de fusion est fondamentalement non parall\u00e8le. Ne vous inqui\u00e9tez pas si c'est la derni\u00e8re \u00e9tape de la requ\u00eate, elle peut quand m\u00eame \u00eatre ex\u00e9cut\u00e9e en parall\u00e8le.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">-- Requ&ecirc;te 2 de TPC-H\nexpliquer (co&ucirc;ts off) s&eacute;lectionner s_acctbal, s_name, n_name, p_partkey, p_mfgr, s_address, s_phone, s_comment\n&agrave; partir de part, fournisseur, partsupp, nation, r&eacute;gion\no&ugrave;\n        p_partkey = ps_partkey\n        et s_suppkey = ps_suppkey\n        et p_size = 36\n        et p_type comme &#039;%BRASS&#039;\n        et s_nationkey = n_nationkey\n        et n_regionkey = r_regionkey\n        et r_name = &#039;AM&Eacute;RIQUE&#039;\n        et ps_supplycost = (\n                s&eacute;lectionner\n                        min(ps_supplycost)\n                &agrave; partir de partsupp, fournisseur, nation, r&eacute;gion\n                o&ugrave;\n                        p_partkey = ps_partkey\n                        et s_suppkey = ps_suppkey\n                        et s_nationkey = n_nationkey\n                        et n_regionkey = r_regionkey\n                        et r_name = &#039;AM&Eacute;RIQUE&#039;\n        )\nclasser par s_acctbal desc, n_name, s_name, p_partkey\nLIMIT 100;\n                                                PLAN DE REQU&Ecirc;TE\n----------------------------------------------------------------------------------------------------------\n Limite\n   -&amp;gt;  Trier\n         Cl&eacute; de tri : supplier.s_acctbal DESC, nation.n_name, supplier.s_name, part.p_partkey\n         -&amp;gt;  Jonction Fusion\n               Condition de fusion : (part.p_partkey = partsupp.ps_partkey)\n               Filtre de jointure : (partsupp.ps_supplycost = (Sous-plan 1))\n               -&amp;gt;  Rassembler la fusion\n                     Travailleurs pr&eacute;vus : 4\n                     -&amp;gt;  Scan d&#039;index parall&egrave;le en utilisant &lt;strong&gt;part_pkey&lt;\/strong&gt; sur part\n                           Filtre : (((p_type)::text ~~ &#039;%BRASS&#039;::text) ET (p_size = 36))\n               -&amp;gt;  Mat&eacute;rialiser\n                     -&amp;gt;  Trier\n                           Cl&eacute; de tri : partsupp.ps_partkey\n                           -&amp;gt;  Boucle imbriqu&eacute;e\n                                 -&amp;gt;  Boucle imbriqu&eacute;e\n                                       Filtre de jointure : (nation.n_regionkey = region.r_regionkey)\n                                       -&amp;gt;  Scan s&eacute;quentiel sur r&eacute;gion\n                                             Filtre : (r_name = &#039;AM&Eacute;RIQUE&#039;::bpchar)\n                                       -&amp;gt;  Jonction par hachage\n                                             Condition de hachage : (supplier.s_nationkey = nation.n_nationkey)\n                                             -&amp;gt;  Scan s&eacute;quentiel sur fournisseur\n                                             -&amp;gt;  Hachage\n                                                   -&amp;gt;  Scan s&eacute;quentiel sur nation\n                                 -&amp;gt;  Scan d&#039;index utilisant idx_partsupp_suppkey sur partsupp\n                                       Condition d&#039;index : (ps_suppkey = supplier.s_suppkey)\n               Sous-plan 1\n                 -&amp;gt;  Agr&eacute;gat\n                       -&amp;gt;  Boucle imbriqu&eacute;e\n                             Filtre de jointure : (nation_1.n_regionkey = region_1.r_regionkey)\n                             -&amp;gt;  Scan s&eacute;quentiel sur r&eacute;gion region_1\n                                   Filtre : (r_name = &#039;AM&Eacute;RIQUE&#039;::bpchar)\n                             -&amp;gt;  Boucle imbriqu&eacute;e\n                                   -&amp;gt;  Boucle imbriqu&eacute;e\n                                         -&amp;gt;  Scan d&#039;index utilisant idx_partsupp_partkey sur partsupp partsupp_1\n                                               Condition d&#039;index : (part.p_partkey = ps_partkey)\n                                         -&amp;gt;  Scan d&#039;index utilisant supplier_pkey sur fournisseur fournisseur_1\n                                               Condition d&#039;index : (s_suppkey = partsupp_1.ps_suppkey)\n                                   -&amp;gt;  Scan d&#039;index utilisant nation_pkey sur nation nation_1\n                                         Condition d&#039;index : (n_nationkey = supplier_1.s_nationkey)<\/code><\/pre>\n<p><\/p>\n<p>Le n\u0153ud \u00ab\u00a0Merge Join\u00a0\u00bb se trouve au-dessus de \u00ab\u00a0Gather Merge\u00a0\u00bb. Ainsi, la fusion n'utilise pas le traitement parall\u00e8le. Mais le n\u0153ud \u00ab\u00a0Scan d'index parall\u00e8le\u00a0\u00bb aide n\u00e9anmoins avec le segment. <code>part_pkey<\/code>.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-po-sekciyam\">Joint par partitions<\/h3>\n<p><\/p>\n<p>Dans PostgreSQL 11 <noindex><a rel=\"nofollow\" href=\"http:\/\/ashutoshpg.blogspot.com\/2017\/12\/partition-wise-joins-divide-and-conquer.html\">joint par partitions<\/a><\/noindex> d\u00e9sactiv\u00e9 par d\u00e9faut : il n\u00e9cessite une planification tr\u00e8s co\u00fbteuse. Les tables avec un partitionnement similaire peuvent \u00eatre jointes partition par partition. Ainsi, Postgres utilisera de plus petites tables de hachage. Chaque jointure de partitions peut \u00eatre parall\u00e8le.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">tpch=# set enable_partitionwise_join=t;\ntpch=# explain (costs off) select * from prt1 t1, prt2 t2\nwhere t1.a = t2.b and t1.b = 0 and t2.b between 0 and 10000;\n                    PLAN DE QU\u00caTE\n---------------------------------------------------\n Append\n   -&gt;  Hash Join\n         Cond de hachage : (t2.b = t1.a)\n         -&gt;  Seq Scan sur prt2_p1 t2\n               Filtre : ((b &gt;= 0) ET (b &lt;= 10000))\n         -&gt;  Hash\n               -&gt;  Seq Scan sur prt1_p1 t1\n                     Filtre : (b = 0)\n   -&gt;  Hash Join\n         Cond de hachage : (t2_1.b = t1_1.a)\n         -&gt;  Seq Scan sur prt2_p2 t2_1\n               Filtre : ((b &gt;= 0) ET (b &lt;= 10000))\n         -&gt;  Hash\n               -&gt;  Seq Scan sur prt1_p2 t1_1\n                     Filtre : (b = 0)\ntpch=# set parallel_setup_cost = 1;\ntpch=# set parallel_tuple_cost = 0.01;\ntpch=# explain (costs off) select * from prt1 t1, prt2 t2\nwhere t1.a = t2.b and t1.b = 0 and t2.b between 0 and 10000;\n                        PLAN DE QU\u00caTE\n-----------------------------------------------------------\n Gather\n   Travailleurs pr\u00e9vus : 4\n   -&gt;  Append parall\u00e8le\n         -&gt;  Hash Join parall\u00e8le\n               Cond de hachage : (t2_1.b = t1_1.a)\n               -&gt;  Seq Scan parall\u00e8le sur prt2_p2 t2_1\n                     Filtre : ((b &gt;= 0) ET (b &lt;= 10000))\n               -&gt;  Hash\n                     -&gt;  Seq Scan parall\u00e8le sur prt1_p2 t1_1\n                           Filtre : (b = 0)\n         -&gt;  Hash Join parall\u00e8le\n               Cond de hachage : (t2.b = t1.a)\n               -&gt;  Seq Scan parall\u00e8le sur prt2_p1 t2\n                     Filtre : ((b &gt;= 0) ET (b &lt;= 10000))\n               -&gt;  Hash\n                     -&gt;  Seq Scan parall\u00e8le sur prt1_p1 t1\n                           Filtre : (b = 0)<\/code><\/pre>\n<p><\/p>\n<p>Principale, une jointure par sections peut \u00eatre parall\u00e8le, seulement si ces sections sont suffisamment grandes.<\/p>\n<p><\/p>\n<h3 id=\"parallelnoe-dopolnenie--parallel-append\">Append parall\u00e8le \u2014 Parallel Append<\/h3>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/parallel-plans.html#PARALLEL-APPEND\">Parallel Append<\/a><\/noindex> peut \u00eatre utilis\u00e9 \u00e0 la place de diff\u00e9rents blocs dans diff\u00e9rents processus de travail. Cela se produit g\u00e9n\u00e9ralement avec des requ\u00eates UNION ALL. Le d\u00e9savantage est un parall\u00e9lisme r\u00e9duit, car chaque processus de travail traite seulement 1 requ\u00eate.<\/p>\n<p><\/p>\n<p>Ici, 2 processus de travail sont lanc\u00e9s, bien que 4 soient inclus.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">tpch=# explain (costs off) select sum(l_quantity) as sum_qty from lineitem where l_shipdate &lt;= date &#039;1998-12-01&#039; - interval &#039;105&#039; day union all select sum(l_quantity) as sum_qty from lineitem where l_shipdate   Parallel Append\n         -&gt;  Aggregate\n               -&gt;  Seq Scan on lineitem\n                     Filter: (l_shipdate   Aggregate\n               -&gt;  Seq Scan on lineitem lineitem_1\n                     Filter: (l_shipdate &lt;= &#039;1998-08-18 00:00:00&#039;::timestamp without time zone)<\/code><\/pre>\n<p><\/p>\n<h3 id=\"samye-vazhnye-peremennye\">Les variables les plus importantes<\/h3>\n<p><\/p>\n<ul>\n<li>WORK_MEM limite la quantit\u00e9 de m\u00e9moire pour chaque processus, pas seulement pour les requ\u00eates : work_mem <em> processus <\/em> connexions = beaucoup de m\u00e9moire.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/runtime-config-resource.html#GUC-MAX-PARALLEL-WORKERS-PER-GATHER\"><code>max_parallel_workers_per_gather<\/code><\/a><\/noindex> \u2014 combien de processus de travail le programme ex\u00e9cutant utilisera pour le traitement parall\u00e8le du plan.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/runtime-config-resource.html#GUC-MAX-WORKER-PROCESSES\"><code>max_worker_processes<\/code><\/a><\/noindex> \u2014 ajuste le nombre total de processus de travail en fonction du nombre de c\u0153urs CPU sur le serveur.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/runtime-config-resource.html#GUC-MAX-WORKER-PROCESSES\"><code>max_parallel_workers<\/code><\/a><\/noindex> \u2014 m\u00eame chose, mais pour les processus de travail parall\u00e8les.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"itogi\">R\u00e9sultats<\/h3>\n<p><\/p>\n<p>Depuis la version 9.6, le traitement parall\u00e8le peut consid\u00e9rablement am\u00e9liorer les performances des requ\u00eates complexes qui scannent de nombreuses lignes ou index. Dans PostgreSQL 10, le traitement parall\u00e8le est activ\u00e9 par d\u00e9faut. N'oubliez pas de le d\u00e9sactiver sur les serveurs avec une charge de travail OLTP importante. Les scans s\u00e9quentiels ou les scans d'index consomment beaucoup de ressources. Si vous n'ex\u00e9cutez pas un rapport sur l'ensemble du jeu de donn\u00e9es, vous pouvez rendre les requ\u00eates plus performantes simplement en ajoutant des index manquants ou en utilisant un bon partitionnement.<\/p>\n<p><\/p>\n<h3 id=\"ssylki\">Liens<\/h3>\n<p><\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/how-parallel-query-works.html\">https:\/\/www.postgresql.org\/docs\/11\/how-parallel-query-works.html<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/parallel-plans.html\">https:\/\/www.postgresql.org\/docs\/11\/parallel-plans.html<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/ashutoshpg.blogspot.com\/2017\/12\/partition-wise-joins-divide-and-conquer.html\">http:\/\/ashutoshpg.blogspot.com\/2017\/12\/partition-wise-joins-divide-and-conquer.html<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/rhaas.blogspot.com\/2016\/04\/postgresql-96-with-parallel-query-vs.html\">http:\/\/rhaas.blogspot.com\/2016\/04\/postgresql-96-with-parallel-query-vs.html<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/amitkapila16.blogspot.com\/2015\/11\/parallel-sequential-scans-in-play.html\">http:\/\/amitkapila16.blogspot.com\/2015\/11\/parallel-sequential-scans-in-play.html<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/write-skew.blogspot.com\/2018\/01\/parallel-hash-for-postgresql.html\">https:\/\/write-skew.blogspot.com\/2018\/01\/parallel-hash-for-postgresql.html<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/rhaas.blogspot.com\/2017\/03\/parallel-query-v2.html\">http:\/\/rhaas.blogspot.com\/2017\/03\/parallel-query-v2.html<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/blog.2ndquadrant.com\/parallel-monster-benchmark\/\">https:\/\/blog.2ndquadrant.com\/parallel-monster-benchmark\/<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/blog.2ndquadrant.com\/parallel-aggregate\/\">https:\/\/blog.2ndquadrant.com\/parallel-aggregate\/<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.depesz.com\/2018\/02\/12\/waiting-for-postgresql-11-support-parallel-btree-index-builds\/\">https:\/\/www.depesz.com\/2018\/02\/12\/waiting-for-postgresql-11-support-parallel-btree-index-builds\/<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/jWIOZzezbb8\">Parall\u00e9lisme dans PostgreSQL 11<\/a><\/noindex><\/li>\n<\/ul>\n<p>Source : <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/southbridge\/blog\/446706\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0426\u041f \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u044f\u0434\u0435\u0440. \u0413\u043e\u0434\u0430\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u044b\u043b\u0430\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0432 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u043e\u0442\u0447\u0435\u0442\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0443 \u0441\u0442\u0440\u043e\u043a \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435, \u043e\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0431\u044b\u0441\u0442\u0440\u0435\u0435, \u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0426\u041f, \u0438 \u0432 PostgreSQL \u044d\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043d\u0430\u0447\u0438\u043d\u0430\u044f \u0441 \u0432\u0435\u0440\u0441\u0438\u0438 9.6. \u041f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u043b\u043e\u0441\u044c 3 \u0433\u043e\u0434\u0430, \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u2014 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u044d\u0442\u0430\u043f\u0430\u0445 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":22879,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-30900","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=\"\u0412 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0426\u041f \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u044f\u0434\u0435\u0440.\" \/>\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\/parallelnye-zaprosy-v-postgresql\" \/>\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\u041f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0432 PostgreSQL | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0426\u041f \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u044f\u0434\u0435\u0440.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql\" \/>\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=\"2019-10-31T18:38:02+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:38:02+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\udd47Requ\u00eates parall\u00e8les dans PostgreSQL | ProHoster","description":"Les CPUs modernes ont beaucoup de c\u0153urs.","canonical_url":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","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\u041f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0432 PostgreSQL | ProHoster","og:description":"\u0412 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0426\u041f \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u044f\u0434\u0435\u0440.","og:url":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","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":"2019-10-31T18:38:02+00:00","article:modified_time":"2019-10-31T18:38:02+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"30900","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":"2026-01-21 03:34:04","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 03:27:06","updated":"2026-01-21 03:34:04","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\/30900","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=30900"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/30900\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media\/22879"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media?parent=30900"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/categories?post=30900"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/tags?post=30900"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}