{"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\/ro\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","title":{"rendered":"Cereri paralele \u00een PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Cereri paralele \u00een PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/04\/bbb4b4d3f8714bbdb9b26ada2f2253b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u00cen procesoarele moderne exist\u0103 foarte multe nuclee. De ani de zile, aplica\u021biile trimiteau cereri \u00een baze de date \u00een paralel. Dac\u0103 este o cerere de raportare pentru un num\u0103r mare de r\u00e2nduri dintr-o tabel\u0103, aceasta se execut\u0103 mai repede atunci c\u00e2nd utilizeaz\u0103 mai multe procesoare, iar \u00een PostgreSQL acest lucru este posibil \u00eencep\u00e2nd cu versiunea 9.6.<\/p>\n<p><\/p>\n<p>Au fost necesari 3 ani pentru a implementa func\u021bia cererilor paralele \u2014 a fost necesar s\u0103 rescriem codul \u00een diferite etape ale execu\u021biei cererilor. \u00cen PostgreSQL 9.6 a fost introdus\u0103 infrastructura pentru \u00eembun\u0103t\u0103\u021birea ulterioar\u0103 a codului. \u00cen versiunile ulterioare, \u0219i alte tipuri de cereri sunt executate \u00een paralel.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3 id=\"ogranicheniya\">Limit\u0103ri<\/h3>\n<p><\/p>\n<ul>\n<li>Nu activa\u021bi execu\u021bia paralel\u0103 dac\u0103 toate nucleele sunt deja ocupate, altfel alte cereri vor fi \u00eencetinite.<\/li>\n<li>Cel mai important, procesarea paralel\u0103 cu valori mari WORK_MEM folose\u0219te mult\u0103 memorie \u2014 fiecare conexiune hash sau sortare ocup\u0103 memorie \u00een volum de work_mem.<\/li>\n<li>Cererile OLTP cu laten\u021b\u0103 mic\u0103 nu pot fi accelerate prin execu\u021bia paralel\u0103. Iar dac\u0103 cererea returneaz\u0103 un singur r\u00e2nd, procesarea paralel\u0103 o va \u00eencetini.<\/li>\n<li>Dezvoltatorii iubesc s\u0103 foloseasc\u0103 benchmark-ul TPC-H. Poate c\u0103 ave\u021bi cereri asem\u0103n\u0103toare pentru o execu\u021bie paralel\u0103 ideal\u0103.<\/li>\n<li>Numai cererile SELECT f\u0103r\u0103 blocare prin predicat sunt executate \u00een paralel.<\/li>\n<li>Uneori, indexarea corect\u0103 este mai bun\u0103 dec\u00e2t scanarea secven\u021bial\u0103 a tabelului \u00een modul paralel.<\/li>\n<li>Suspendarea cererilor \u0219i cursurile nu sunt suportate.<\/li>\n<li>Func\u021biile fereastr\u0103 \u0219i func\u021biile agregate ale seturilor ordonate nu sunt paralele.<\/li>\n<li>Nu ob\u021bine\u021bi nimic \u00een sarcina de lucru de intrare-ie\u0219ire.<\/li>\n<li>Nu exist\u0103 algoritmi de sortare paralele. Dar cererile cu sort\u0103ri pot fi executate \u00een paralel \u00een anumite aspecte.<\/li>\n<li>\u00cenlocui\u021bi CTE (WITH \u2026) cu un SELECT \u00eencorporat pentru a activa procesarea paralel\u0103.<\/li>\n<li>\u00cenf\u0103\u0219ur\u0103turile de date externe nu suport\u0103 \u00eenc\u0103 procesarea paralel\u0103 (dar ar putea!)<\/li>\n<li>FULL OUTER JOIN nu este suportat.<\/li>\n<li>max_rows dezactiveaz\u0103 procesarea paralel\u0103.<\/li>\n<li>Dac\u0103 \u00een cerere exist\u0103 o func\u021bie care nu este marcat\u0103 ca PARALLEL SAFE, aceasta va fi unic\u0103.<\/li>\n<li>Nivelul de izolare al tranzac\u021biei SERIALIZABLE dezactiveaz\u0103 procesarea paralel\u0103.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"testovaya-sreda\">Mediu de testare<\/h3>\n<p><\/p>\n<p>Dezvoltatorii PostgreSQL au \u00eencercat s\u0103 reduc\u0103 timpul de r\u0103spuns al cererilor benchmark-ului TPC-H. Desc\u0103rca\u021bi benchmark-ul \u0219i <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">adapta\u021bi-l la PostgreSQL<\/a><\/noindex>. Aceasta este o utilizare neoficial\u0103 a benchmark-ului TPC-H \u2014 nu pentru compararea bazelor de date sau a echipamentelor.<\/p>\n<p><\/p>\n<ol>\n<li>Desc\u0103rca\u021bi TPC-H_Tools_v2.17.3.zip (sau o versiune mai recent\u0103) <noindex><a rel=\"nofollow\" href=\"http:\/\/www.tpc.org\/tpc_documents_current_versions\/current_specifications.asp\">de pe site-ul TPC<\/a><\/noindex>.<\/li>\n<li>Renumi\u021bi makefile.suite \u00een Makefile \u0219i modifica\u021bi-l conform instruc\u021biunilor de aici: <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">https:\/\/github.com\/tvondra\/pg_tpch <\/a><\/noindex>. Compila\u021bi codul cu comanda make.<\/li>\n<li>Genera\u021bi datele: <code>.\\\/dbgen -s 10<\/code> creeaz\u0103 o baz\u0103 de date de 23 GB. Acest lucru este suficient pentru a observa diferen\u021ba de performan\u021b\u0103 \u00eentre interog\u0103rile paralele \u0219i cele neparalele.<\/li>\n<li>Conversa\u021bi fi\u0219ierele <code>tbl<\/code> \u00een <code>csv cu for<\/code> \u0219i <code>sed<\/code>.<\/li>\n<li>Clonare repository <code>pg_tpch<\/code> \u0219i copia\u021bi fi\u0219ierele <code>csv<\/code> \u00een <code>pg_tpch\\\/dss\\\/data<\/code>.<\/li>\n<li>Crea\u021bi interog\u0103rile cu comanda <code>qgen<\/code>.<\/li>\n<li>\u00cenc\u0103rca\u021bi datele \u00een baz\u0103 cu comanda <code>.\\\/tpch.sh<\/code>.<\/li>\n<\/ol>\n<p><\/p>\n<h3 id=\"parallelnoe-posledovatelnoe-skanirovanie\">Scanare secven\u021bial\u0103 paralel\u0103<\/h3>\n<p><\/p>\n<p>Aceasta poate fi mai rapid\u0103 nu din cauza citirii paralele, ci pentru c\u0103 datele sunt dispersate pe multe nuclee ale CPU-ului. \u00cen sistemele de operare moderne, fi\u0219ierele de date PostgreSQL sunt bine cache-uie. Cu citirea anticipat\u0103, se pot ob\u021bine blocuri mai mari din magazin dec\u00e2t cererea demonului PG. Prin urmare, performan\u021ba interog\u0103rii nu este limitat\u0103 de intr\u0103rile \u0219i ie\u0219irile discului. Consuma cicluri CPU pentru a:<\/p>\n<p><\/p>\n<ul>\n<li>citi r\u00e2nduri c\u00e2te unul de pe paginile tabelului;<\/li>\n<li>compara valorile r\u00e2ndurilor \u0219i condi\u021biile <code>WHERE<\/code>.<\/li>\n<\/ul>\n<p><\/p>\n<p>S\u0103 execut\u0103m o interogare simpl\u0103 <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;\nPLANUL INTEROG\u0102RII\n--------------------------------------------------------------------------------------------------------------------------\nScanare Secven\u021bial\u0103 pe lineitem (cost=0.00..1964772.00 rows=58856235 width=5) (timp efectiv=0.014..16951.669 rows=58839715 loops=1)\nFiltru: (l_shipdate &lt;= &#039;1998-08-18 00:00:00&#039;::timestamp f\u0103r\u0103 fus orar)\nR\u00e2nduri eliminate de Filtru: 1146337\nTimp de planificare: 0.203 ms\nTimp de execu\u021bie: 19035.100 ms<\/code><\/pre>\n<p><\/p>\n<p>Scanarea secven\u021bial\u0103 ofer\u0103 prea multe r\u00e2nduri f\u0103r\u0103 agregare, astfel \u00eenc\u00e2t interogarea este executat\u0103 pe un singur nucleu CPU.<\/p>\n<p><\/p>\n<p>Dac\u0103 ad\u0103ug\u0103m <code>SUM()<\/code>, se observ\u0103 c\u0103 dou\u0103 procese de lucru ajut\u0103 la accelerarea interog\u0103rii:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">explain analyze select sum(l_quantity) as sum_qty from lineitem where l_shipdate &lt;= date &#039;1998-12-01&#039; - interval &#039;105&#039; day;\nPLANUL INTEROG\u0102RII\n----------------------------------------------------------------------------------------------------------------------------------------------------\nFinalizeaz\u0103 Agregarea (cost=1589702.14..1589702.15 rows=1 width=32) (timp efectiv=8553.365..8553.365 rows=1 loops=1)\n-&gt; Adun\u0103 (cost=1589701.91..1589702.12 rows=2 width=32) (timp efectiv=8553.241..8555.067 rows=3 loops=1)\nLucr\u0103tori Planifica\u021bi: 2\nLucr\u0103tori Lansati: 2\n-&gt; Agregare Par\u021bial\u0103 (cost=1588701.91..1588701.92 rows=1 width=32) (timp efectiv=8547.546..8547.546 rows=1 loops=3)\n-&gt; Scanare Secven\u021bial\u0103 Paralel\u0103 pe lineitem (cost=0.00..1527393.33 rows=24523431 width=5) (timp efectiv=0.038..5998.417 rows=19613238 loops=3)\nFiltru: (l_shipdate &lt;= &#039;1998-08-18 00:00:00&#039;::timestamp f\u0103r\u0103 fus orar)\nR\u00e2nduri eliminate de Filtru: 382112\nTimp de planificare: 0.241 ms\nTimp de execu\u021bie: 8555.131 ms<\/code><\/pre>\n<p><\/p>\n<h3 id=\"parallelnaya-agregaciya\">Agregare paralel\u0103<\/h3>\n<p><\/p>\n<p>Nodul \u201eScan Paralel Seq\u201d produce r\u00e2nduri pentru agregarea par\u021bial\u0103. Nodul \u201eAgregare Par\u021bial\u0103\u201d micsoreaz\u0103 aceste r\u00e2nduri cu ajutorul <code>SUM()<\/code>. La sf\u00e2r\u0219it, contorul SUM din fiecare proces de lucru este adunat de nodul \u201eGather\u201d.<\/p>\n<p><\/p>\n<p>Rezultatul final este calculat de nodul \u201eFinalize Aggregate\u201d. Dac\u0103 ave\u021bi func\u021bii proprii de agregare, nu uita\u021bi s\u0103 le marca\u021bi ca \u201eparallel safe\u201d.<\/p>\n<p><\/p>\n<h3 id=\"kolichestvo-rabochih-processov\">Num\u0103rul de procese de lucru<\/h3>\n<p><\/p>\n<p>Num\u0103rul de procese de lucru poate fi crescut f\u0103r\u0103 a reporni serverul:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">explain analyze select sum(l_quantity) as sum_qty from lineitem where l_shipdate &lt;= date &#039;1998-12-01&#039; - interval &#039;105&#039; day;\nPLANUL INTEROG\u0102RII\n----------------------------------------------------------------------------------------------------------------------------------------------------\nFinalizeaz\u0103 Agregarea (cost=1589702.14..1589702.15 rows=1 width=32) (timp efectiv=8553.365..8553.365 rows=1 loops=1)\n-&gt; Adun\u0103 (cost=1589701.91..1589702.12 rows=2 width=32) (timp efectiv=8553.241..8555.067 rows=3 loops=1)\nLucr\u0103tori Planifica\u021bi: 2\nLucr\u0103tori Lansati: 2\n-&gt; Agregare Par\u021bial\u0103 (cost=1588701.91..1588701.92 rows=1 width=32) (timp efectiv=8547.546..8547.546 rows=1 loops=3)\n-&gt; Scanare Secven\u021bial\u0103 Paralel\u0103 pe lineitem (cost=0.00..1527393.33 rows=24523431 width=5) (timp efectiv=0.038..5998.417 rows=19613238 loops=3)\nFiltru: (l_shipdate &lt;= &#039;1998-08-18 00:00:00&#039;::timestamp f\u0103r\u0103 fus orar)\nR\u00e2nduri eliminate de Filtru: 382112\nTimp de planificare: 0.241 ms\nTimp de execu\u021bie: 8555.131 ms<\/code><\/pre>\n<p><\/p>\n<p>Ce se \u00eent\u00e2mpl\u0103 aici? Num\u0103rul de procese de lucru s-a dublat, iar cererea a devenit de doar 1,6599 ori mai rapid\u0103. Calculul este interesant. Aveam 2 procese de lucru \u0219i 1 lider. Dup\u0103 modificare, avem 4+1.<\/p>\n<p><\/p>\n<p>Accelera\u021bia maxim\u0103 ob\u021binut\u0103 prin procesare paralel\u0103 este: 5\/3 = 1,66(6) ori.<\/p>\n<p><\/p>\n<h2 id=\"kak-eto-rabotaet\">Cum func\u021bioneaz\u0103?<\/h2>\n<p><\/p>\n<h3 id=\"processy\">Procese<\/h3>\n<p><\/p>\n<p>Executarea cererii \u00eencepe \u00eentotdeauna cu procesul de conducere. Liderul se ocup\u0103 de tot ce este nep\u0103truns \u0219i de o parte din procesarea paralel\u0103. Altele procese care execut\u0103 acelea\u0219i cereri sunt numite procese de lucru. Procesarea paralel\u0103 folose\u0219te infrastructura <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/bgworker.html\">proceselor de lucru de fundal dinamice<\/a><\/noindex> (\u00eencep\u00e2nd cu versiunea 9.4). Deoarece alte p\u0103r\u021bi ale PostgreSQL folosesc procese, nu fire, o cerere cu 3 procese de lucru ar putea fi cu 4 ori mai rapid\u0103 dec\u00e2t procesarea tradi\u021bional\u0103.<\/p>\n<p><\/p>\n<h3 id=\"vzaimodeystvie\">Interac\u021biune<\/h3>\n<p><\/p>\n<p>Procesele de lucru comunic\u0103 cu liderul printr-o coad\u0103 de mesaje (bazat\u0103 pe memorie comun\u0103). Fiecare proces are 2 cozi: pentru erori \u0219i pentru tupluri.<\/p>\n<p><\/p>\n<h3 id=\"skolko-nuzhno-rabochih-processov\">C\u00e2te procese de lucru sunt necesare?<\/h3>\n<p><\/p>\n<p>Limitarea minim\u0103 este stabilit\u0103 de parametrul <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>. Apoi, executorul cererii ia procese de lucru din pool-ul limitat de parametrul <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>. Ultima limitare este <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>, adic\u0103 num\u0103rul total de procese de fundal.<\/p>\n<p><\/p>\n<p>Dac\u0103 nu s-a reu\u0219it alocarea unui proces de lucru, procesarea va fi uniprotocarea.<\/p>\n<p><\/p>\n<p>Planificatorul de cereri poate reduce procesele de lucru \u00een func\u021bie de dimensiunea tabelei sau a indexului. Pentru aceasta, exist\u0103 parametrii <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> \u0219i <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 tabel =&gt; 1 muncitor\n24MB tabel =&gt; 2 muncitori\n72MB tabel =&gt; 3 muncitori\nx =&gt; log(x \/ min_parallel_table_scan_size) \/ log(3) + 1 muncitor<\/code><\/pre>\n<p><\/p>\n<p>De fiecare dat\u0103 c\u00e2nd tabela este de 3 ori mai mare dec\u00e2t <code>min_parallel_(index|table)_scan_size<\/code>, Postgres adaug\u0103 un proces de lucru. Num\u0103rul de procese de lucru nu se bazeaz\u0103 pe costuri. Dependen\u021ba circular\u0103 \u00eengreuneaz\u0103 implement\u0103rile complexe. \u00cen schimb, planificatorul folose\u0219te reguli simple.<\/p>\n<p><\/p>\n<p>\u00cen practic\u0103, aceste reguli nu sunt \u00eentotdeauna adecvate pentru produc\u021bie, a\u0219a c\u0103 se poate modifica num\u0103rul de procese de lucru pentru o tabel\u0103 specific\u0103: ALTER TABLE \u2026 SET (<code>parallel_workers = N<\/code>).<\/p>\n<p><\/p>\n<h3 id=\"pochemu-parallelnaya-obrabotka-ne-ispolzuetsya\">De ce nu se utilizeaz\u0103 procesarea paralel\u0103?<\/h3>\n<p><\/p>\n<p>Pe l\u00e2ng\u0103 lunga list\u0103 de restric\u021bii, exist\u0103 \u0219i verific\u0103ri ale costurilor:<\/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>costul_set\u0103rii_paralele<\/code><\/a><\/noindex> \u2014 pentru a evita procesarea paralel\u0103 a cererilor scurte. Acest parametru estimeaz\u0103 timpul pentru preg\u0103tirea memoriei, pornirea procesului \u0219i schimbul ini\u021bial de date.<\/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>costul_tuple-urilor_paralele<\/code><\/a><\/noindex>: comunicarea liderului cu lucr\u0103torii poate dura propor\u021bional cu num\u0103rul de tuple-uri din procesele de lucru. Acest parametru calculeaz\u0103 costurile schimbului de date.<\/p>\n<p><\/p>\n<h3 id=\"soedineniya-vlozhennyh-ciklov--nested-loop-join\">\u00cembin\u0103rile ciclice \u00eenf\u0103\u0219urate \u2014 Nested Loop Join<\/h3>\n<p><\/p>\n<pre><code class=\"plaintext\">PostgreSQL 9.6+ poate executa bucle imbricate \u00een moduri paralele \u2014 aceasta este o opera\u021biune simpl\u0103.\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 QUERY PLAN\n--------------------------------------------------------------------------------------\n Finalize GroupAggregate\n Group Key: customer.c_custkey\n -&gt; Gather Merge\n Workers Planned: 4\n -&gt; Partial GroupAggregate\n Group Key: customer.c_custkey\n -&gt; Nested Loop Left Join\n -&gt; Parallel Index Only Scan using customer_pkey on customer\n -&gt; Index Scan using idx_orders_custkey on orders\n Index Cond: (customer.c_custkey = o_custkey)\n Filter: ((o_comment)::text !~~ '%specialposits%'::text)<\/code><\/pre>\n<p><\/p>\n<p>Colectarea se face \u00een ultima etap\u0103, astfel c\u0103 Nested Loop Left Join \u2014 este o opera\u021bie paralel\u0103. Parallel Index Only Scan a ap\u0103rut doar \u00een versiunea 10. Func\u021bioneaz\u0103 similar cu scanarea secven\u021bial\u0103 paralel\u0103. Condi\u021bia <code>c_custkey = o_custkey<\/code> cite\u0219te o comand\u0103 pentru fiecare linie a clientului. A\u0219adar, nu este paralel.<\/p>\n<p><\/p>\n<h3 id=\"hesh-soedinenie--hash-join\">\u00cembinarea prin hashtable \u2014 Hash Join<\/h3>\n<p><\/p>\n<p>Fiecare proces de lucru \u00ee\u0219i creeaz\u0103 propria tabel\u0103 hash p\u00e2n\u0103 la PostgreSQL 11. \u0218i dac\u0103 procesele sunt mai mult de patru, performan\u021ba nu va cre\u0219te. \u00cen noua versiune, tabela hash este comun\u0103. Fiecare proces de lucru poate utiliza WORK_MEM pentru a crea o tabel\u0103 hash.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">select\n        l_shipmode,\n        sum(case\n                when o_orderpriority = '1-URGENT'\n                        or o_orderpriority = '2-HIGH'\n                        then 1\n                else 0\n        end) as high_line_count,\n        sum(case\n                when o_orderpriority  '1-URGENT'\n                        and o_orderpriority  '2-HIGH'\n                        then 1\n                else 0\n        end) as low_line_count\nfrom\n        orders,\n        lineitem\nwhere\n        o_orderkey = l_orderkey\n        and l_shipmode in ('MAIL', 'AIR')\n        and l_commitdate &lt; l_receiptdate\n        and l_shipdate = date '1996-01-01'\n        and l_receiptdate   Finalize GroupAggregate  (cost=1964755.66..1966196.11 rows=7 width=27) (actual time=7579.590..7579.591 rows=1 loops=1)\n         Group Key: lineitem.l_shipmode\n         -&gt;  Gather Merge  (cost=1964755.66..1966195.83 rows=28 width=27) (actual time=7559.593..7922.319 rows=6 loops=1)\n               Workers Planned: 4\n               Workers Launched: 4\n               -&gt;  Partial GroupAggregate  (cost=1963755.61..1965192.44 rows=7 width=27) (actual time=7548.103..7564.592 rows=2 loops=5)\n                     Group Key: lineitem.l_shipmode\n                     -&gt;  Sort  (cost=1963755.61..1963935.20 rows=71838 width=27) (actual time=7530.280..7539.688 rows=62519 loops=5)\n                           Sort Key: lineitem.l_shipmode\n                           Sort Method: external merge  Disk: 2304kB\n                           Worker 0:  Sort Method: external merge  Disk: 2064kB\n                           Worker 1:  Sort Method: external merge  Disk: 2384kB\n                           Worker 2:  Sort Method: external merge  Disk: 2264kB\n                           Worker 3:  Sort Method: external merge  Disk: 2336kB\n                           -&gt;  Parallel Hash Join  (cost=382571.01..1957960.99 rows=71838 width=27) (actual time=7036.917..7499.692 rows=62519 loops=5)\n                                 Hash Cond: (lineitem.l_orderkey = orders.o_orderkey)\n                                 -&gt;  Parallel Seq Scan on lineitem  (cost=0.00..1552386.40 rows=71838 width=19) (actual time=0.583..4901.063 rows=62519 loops=5)\n                                       Filter: ((l_shipmode = ANY ('{MAIL,AIR}'::bpchar[])) AND (l_commitdate &lt; l_receiptdate) AND (l_shipdate = '1996-01-01'::date) AND (l_receiptdate   Parallel Hash  (cost=313722.45..313722.45 rows=3750045 width=20) (actual time=2011.518..2011.518 rows=3000000 loops=5)\n                                       Buckets: 65536  Batches: 256  Memory Usage: 3840kB\n                                       -&gt;  Parallel Seq Scan on orders  (cost=0.00..313722.45 rows=3750045 width=20) (actual time=0.029..995.948 rows=3000000 loops=5)\n Planning Time: 0.977 ms\n Execution Time: 7923.770 ms<\/code><\/pre>\n<p><\/p>\n<p>Interogarea 12 din TPC-H arat\u0103 clar un join hash paralel. Fiecare proces lucreaz\u0103 la crearea unei tabele hash comune.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-sliyaniem--merge-join\">\u00cembinarea \u2014 Merge Join<\/h3>\n<p><\/p>\n<p>\u00cembinarea este prin natura sa non-paralel\u0103. Nu v\u0103 face\u021bi griji dac\u0103 aceasta este ultima etap\u0103 a interog\u0103rii \u2014 poate totu\u0219i fi executat\u0103 \u00een paralel.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">-- Interogare 2 din TPC-H\nexplain (costuri dezactivate) select s_acctbal, s_name, n_name, p_partkey, p_mfgr, s_address, s_phone, s_comment\nfrom    part, supplier, partsupp, nation, region\nwhere\n        p_partkey = ps_partkey\n        and s_suppkey = ps_suppkey\n        and p_size = 36\n        and p_type like &#039;%BRASS&#039;\n        and s_nationkey = n_nationkey\n        and n_regionkey = r_regionkey\n        and r_name = &#039;AMERICA&#039;\n        and ps_supplycost = (\n                select\n                        min(ps_supplycost)\n                from    partsupp, supplier, nation, region\n                where\n                        p_partkey = ps_partkey\n                        and s_suppkey = ps_suppkey\n                        and s_nationkey = n_nationkey\n                        and n_regionkey = r_regionkey\n                        and r_name = &#039;AMERICA&#039;\n        )\norder by s_acctbal desc, n_name, s_name, p_partkey\nLIMIT 100;\n                                                PLAN DE INTEROGARE\n----------------------------------------------------------------------------------------------------------\n Limit\n   -&amp;gt;  Sort\n         Cheie Sortare: supplier.s_acctbal DESC, nation.n_name, supplier.s_name, part.p_partkey\n         -&amp;gt;  Merge Join\n               Condi\u021bie de &icirc;mbinare: (part.p_partkey = partsupp.ps_partkey)\n               Filtru de &icirc;mbinare: (partsupp.ps_supplycost = (SubPlan 1))\n               -&amp;gt;  Gather Merge\n                     Lucr\u0103tori planifica\u021bi: 4\n                     -&amp;gt;  Scan de Indice Paralel folosind &lt;strong&gt;part_pkey&lt;\/strong&gt; on part\n                           Filtru: (((p_type)::text ~~ &#039;%BRASS&#039;::text) \u0218I (p_size = 36))\n               -&amp;gt;  Materialize\n                     -&amp;gt;  Sort\n                           Cheie Sortare: partsupp.ps_partkey\n                           -&amp;gt;  Nested Loop\n                                 -&amp;gt;  Nested Loop\n                                       Filtru de &icirc;mbinare: (nation.n_regionkey = region.r_regionkey)\n                                       -&amp;gt;  Scan Secven\u021bial pe region\n                                             Filtru: (r_name = &#039;AMERICA&#039;::bpchar)\n                                       -&amp;gt;  Hash Join\n                                             Condi\u021bie Hash: (supplier.s_nationkey = nation.n_nationkey)\n                                             -&amp;gt;  Scan Secven\u021bial pe supplier\n                                             -&amp;gt;  Hash\n                                                   -&amp;gt;  Scan Secven\u021bial pe nation\n                                 -&amp;gt;  Scan de Indice folosind idx_partsupp_suppkey pe partsupp\n                                       Condi\u021bie de Indice: (ps_suppkey = supplier.s_suppkey)\n               SubPlan 1\n                 -&amp;gt;  Aggregate\n                       -&amp;gt;  Nested Loop\n                             Filtru de &icirc;mbinare: (nation_1.n_regionkey = region_1.r_regionkey)\n                             -&amp;gt;  Scan Secven\u021bial pe region region_1\n                                   Filtru: (r_name = &#039;AMERICA&#039;::bpchar)\n                             -&amp;gt;  Nested Loop\n                                   -&amp;gt;  Nested Loop\n                                         -&amp;gt;  Scan de Indice folosind idx_partsupp_partkey pe partsupp partsupp_1\n                                               Condi\u021bie de Indice: (part.p_partkey = ps_partkey)\n                                         -&amp;gt;  Scan de Indice folosind supplier_pkey pe supplier supplier_1\n                                               Condi\u021bie de Indice: (s_suppkey = partsupp_1.ps_suppkey)\n                                   -&amp;gt;  Scan de Indice folosind nation_pkey pe nation nation_1\n                                         Condi\u021bie de Indice: (n_nationkey = supplier_1.s_nationkey)<\/code><\/pre>\n<p><\/p>\n<p>Nodul \u201eMerge Join\u201d se afl\u0103 deasupra \u201eGather Merge\u201d. A\u0219adar, fuziunea nu folose\u0219te procesarea paralel\u0103. \u00cens\u0103 nodul \u201eScan Indice Paralel\u201d ajut\u0103 totu\u0219i cu segmentul. <code>part_pkey<\/code>.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-po-sekciyam\">\u00cembinarea pe sec\u021biuni<\/h3>\n<p><\/p>\n<p>\u00cen PostgreSQL 11 <noindex><a rel=\"nofollow\" href=\"http:\/\/ashutoshpg.blogspot.com\/2017\/12\/partition-wise-joins-divide-and-conquer.html\">\u00eembinarea pe sec\u021biuni<\/a><\/noindex> dezactivat implicit: are un plan foarte costisitor. Tabele cu sec\u021bionare similare pot fi \u00eembinate sec\u021biune cu sec\u021biune. Astfel, Postgres va utiliza table hash mai mici. Fiecare \u00eembinare de sec\u021biuni poate fi paralel\u0103.<\/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 INTEROGARE\n---------------------------------------------------\n Append\n   -&gt;  Hash Join\n         Condi\u021bie Hash: (t2.b = t1.a)\n         -&gt;  Scanare Secven\u021bial\u0103 pe prt2_p1 t2\n               Filtru: ((b &gt;= 0) \u0218I (b &lt;= 10000))\n         -&gt;  Hash\n               -&gt;  Scanare Secven\u021bial\u0103 pe prt1_p1 t1\n                     Filtru: (b = 0)\n   -&gt;  Hash Join\n         Condi\u021bie Hash: (t2_1.b = t1_1.a)\n         -&gt;  Scanare Secven\u021bial\u0103 pe prt2_p2 t2_1\n               Filtru: ((b &gt;= 0) \u0218I (b &lt;= 10000))\n         -&gt;  Hash\n               -&gt;  Scanare Secven\u021bial\u0103 pe prt1_p2 t1_1\n                     Filtru: (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 INTEROGARE\n-----------------------------------------------------------\n Gather\n   Lucr\u0103tori Planifica\u021bi: 4\n   -&gt;  \u00cembinare paralel\u0103\n         -&gt;  \u00cembinare Hash Paralel\u0103\n               Condi\u021bie Hash: (t2_1.b = t1_1.a)\n               -&gt;  Scanare Secven\u021bial\u0103 Paralel\u0103 pe prt2_p2 t2_1\n                     Filtru: ((b &gt;= 0) \u0218I (b &lt;= 10000))\n               -&gt;  Hash\n                     -&gt;  Scanare Secven\u021bial\u0103 Paralel\u0103 pe prt1_p2 t1_1\n                           Filtru: (b = 0)\n         -&gt;  \u00cembinare Hash Paralel\u0103\n               Condi\u021bie Hash: (t2.b = t1.a)\n               -&gt;  Scanare Secven\u021bial\u0103 Paralel\u0103 pe prt2_p1 t2\n                     Filtru: ((b &gt;= 0) \u0218I (b &lt;= 10000))\n               -&gt;  Hash\n                     -&gt;  Scanare Secven\u021bial\u0103 Paralel\u0103 pe prt1_p1 t1\n                           Filtru: (b = 0)<\/code><\/pre>\n<p><\/p>\n<p>Principalul aspect, \u00eembinarea pe sec\u021biuni este paralel\u0103, doar dac\u0103 acele sec\u021biuni sunt suficient de mari.<\/p>\n<p><\/p>\n<h3 id=\"parallelnoe-dopolnenie--parallel-append\">Ad\u0103ugare paralel\u0103 \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> poate fi utilizat \u00een locul diferitelor blocuri \u00een diferite procese de lucru. De obicei, acest lucru se \u00eent\u00e2mpl\u0103 cu interog\u0103ri UNION ALL. Dezavantajul este c\u0103 exist\u0103 mai pu\u021bin paralelism, deoarece fiecare proces de lucru proceseaz\u0103 doar o interogare.<\/p>\n<p><\/p>\n<p>Aici sunt active 2 procese de lucru, de\u0219i sunt activate 4.<\/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 &lt;= date &#039;2000-12-01&#039; - interval &#039;105&#039; day;\n                                           QUERY PLAN\n------------------------------------------------------------------------------------------------\n Gather\n   Workers Planned: 2\n   -&gt;  Parallel Append\n         -&gt;  Aggregate\n               -&gt;  Seq Scan on lineitem\n                     Filter: (l_shipdate &lt;= &#039;2000-08-18 00:00:00&#039;::timestamp without time zone)\n         -&gt;  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\">Cele mai importante variabile<\/h3>\n<p><\/p>\n<ul>\n<li>WORK_MEM limiteaz\u0103 cantitatea de memorie pentru fiecare proces, nu doar pentru interog\u0103ri: work_mem <em> procese <\/em> conexiuni = foarte mult\u0103 memorie.<\/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 c\u00e2te procese de lucru va utiliza programul pentru procesarea paralel\u0103 din 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 ajusteaz\u0103 num\u0103rul total de procese de lucru la num\u0103rul de nuclee CPU de pe server.<\/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 acela\u0219i lucru, dar pentru procese de lucru paralele.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"itogi\">Concluzii<\/h3>\n<p><\/p>\n<p>\u00cencep\u00e2nd cu versiunea 9.6, procesarea paralel\u0103 poate \u00eembun\u0103t\u0103\u021bi semnificativ performan\u021ba interog\u0103rilor complexe care scaneaz\u0103 multe r\u00e2nduri sau indexuri. \u00cen PostgreSQL 10, procesarea paralel\u0103 este activat\u0103 implicit. Nu uita\u021bi s\u0103 o dezactiva\u021bi pe serverele cu o sarcin\u0103 de lucru OLTP mare. Scan\u0103rile secven\u021biale sau scan\u0103rile indexurilor consum\u0103 foarte multe resurse. Dac\u0103 nu efectua\u021bi un raport pe \u00eentregul set de date, interog\u0103rile pot fi mai eficiente, ad\u0103ug\u00e2nd pur \u0219i simplu indexurile lips\u0103 sau folosind o parti\u021bionare corect\u0103.<\/p>\n<p><\/p>\n<h3 id=\"ssylki\">Linkuri<\/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\">Paralelism \u00een PostgreSQL 11<\/a><\/noindex><\/li>\n<\/ul>\n<p>Sursa: <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.1 - 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\/ro\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"ro_RO\" \/>\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\/ro\/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\udd47Interog\u0103ri paralele \u00een PostgreSQL | ProHoster","description":"\u00cen procesoare moderne sunt foarte multe nuclee.","canonical_url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"ro_RO","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\/ro\/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\/ro\/wp-json\/wp\/v2\/posts\/30900","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/comments?post=30900"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/30900\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media\/22879"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media?parent=30900"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/categories?post=30900"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/tags?post=30900"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}