{"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\/cs\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","title":{"rendered":"P\u0159enos paraleln\u00edch dotaz\u016f v PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"P\u0159enos paraleln\u00edch dotaz\u016f v PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/04\/bbb4b4d3f8714bbdb9b26ada2f2253b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nV modern\u00edch procesorech je mnoho jader. Aplikace pos\u00edlaly \u017e\u00e1dosti do datab\u00e1z\u00ed paraleln\u011b po cel\u00e1 l\u00e9ta. Pokud jde o dotaz na mnoho \u0159\u00e1dk\u016f v tabulce, je rychlej\u0161\u00ed, kdy\u017e vyu\u017e\u00edv\u00e1 v\u00edce procesor\u016f, a v PostgreSQL je to mo\u017en\u00e9 od verze 9.6.<\/p>\n<p><\/p>\n<p>Trvalo t\u0159i roky, ne\u017e byla implementov\u00e1na funkce paraleln\u00edch dotaz\u016f \u2013 bylo nutn\u00e9 p\u0159epsat k\u00f3d v r\u016fzn\u00fdch f\u00e1z\u00edch prov\u00e1d\u011bn\u00ed dotaz\u016f. V PostgreSQL 9.6 byla vytvo\u0159ena infrastruktura pro dal\u0161\u00ed zlep\u0161en\u00ed k\u00f3du. V n\u00e1sleduj\u00edc\u00edch verz\u00edch se z\u00e1rove\u0148 prov\u00e1d\u00ed i jin\u00e9 typy dotaz\u016f.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3 id=\"ogranicheniya\">Omezen\u00ed<\/h3>\n<p><\/p>\n<ul>\n<li>Nezap\u00ednejte paraleln\u00ed prov\u00e1d\u011bn\u00ed, pokud jsou v\u0161echna j\u00e1dra ji\u017e obsazena, jinak budou ostatn\u00ed dotazy zpomalovat.<\/li>\n<li>Nejd\u016fle\u017eit\u011bj\u0161\u00ed je, \u017ee paraleln\u00ed zpracov\u00e1n\u00ed s vysok\u00fdmi hodnotami WORK_MEM vyu\u017e\u00edv\u00e1 hodn\u011b pam\u011bti \u2013 ka\u017ed\u00e9 hash spojen\u00ed nebo t\u0159\u00edd\u011bn\u00ed zab\u00edr\u00e1 pam\u011b\u0165 ve velikosti work_mem.<\/li>\n<li>OLTP dotazy s n\u00edzkou latenc\u00ed nelze urychlit paraleln\u00edm prov\u00e1d\u011bn\u00edm. A pokud dotaz vrac\u00ed jeden \u0159\u00e1dek, paraleln\u00ed zpracov\u00e1n\u00ed ho pouze zpomal\u00ed.<\/li>\n<li>V\u00fdvoj\u00e1\u0159i r\u00e1di pou\u017e\u00edvaj\u00ed benchmark TPC-H. Mo\u017en\u00e1 m\u00e1te podobn\u00e9 dotazy pro ide\u00e1ln\u00ed paraleln\u00ed proveden\u00ed.<\/li>\n<li>Pouze dotazy SELECT bez predik\u00e1tn\u00ed blokace se vykon\u00e1vaj\u00ed paraleln\u011b.<\/li>\n<li>N\u011bkdy je spr\u00e1vn\u00e1 indexace lep\u0161\u00ed ne\u017e sekven\u010dn\u00ed skenov\u00e1n\u00ed tabulky v paraleln\u00edm re\u017eimu.<\/li>\n<li>Pozastaven\u00ed dotaz\u016f a kurzory nejsou podporov\u00e1ny.<\/li>\n<li>Okna a agreg\u00e1tn\u00ed funkce uspo\u0159\u00e1dan\u00fdch sad nejsou paraleln\u00ed.<\/li>\n<li>V pracovn\u00ed z\u00e1t\u011b\u017ei s vstupem a v\u00fdstupem nez\u00edsk\u00e1te nic.<\/li>\n<li>Paraleln\u00ed algoritmy t\u0159\u00edd\u011bn\u00ed neexistuj\u00ed. Nicm\u00e9n\u011b, dotazy s t\u0159\u00edd\u011bn\u00edm mohou b\u00fdt prov\u00e1d\u011bny paraleln\u011b v n\u011bkter\u00fdch aspektech.<\/li>\n<li>Nahra\u010fte CTE (WITH \u2026) vno\u0159en\u00fdm SELECT, abyste zahrnuli paraleln\u00ed zpracov\u00e1n\u00ed.<\/li>\n<li>Obaly extern\u00edch dat zat\u00edm nepodporuj\u00ed paraleln\u00ed zpracov\u00e1n\u00ed (a mohly by!).<\/li>\n<li>FULL OUTER JOIN nen\u00ed podporov\u00e1n.<\/li>\n<li>max_rows deaktivuje paraleln\u00ed zpracov\u00e1n\u00ed.<\/li>\n<li>Pokud je v dotazu funkce, kter\u00e1 nen\u00ed ozna\u010dena jako PARALLEL SAFE, bude jednovl\u00e1knov\u00fd.<\/li>\n<li>\u00darove\u0148 izolace transakce SERIALIZABLE deaktivuje paraleln\u00ed zpracov\u00e1n\u00ed.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"testovaya-sreda\">Testovac\u00ed prost\u0159ed\u00ed<\/h3>\n<p><\/p>\n<p>V\u00fdvoj\u00e1\u0159i PostgreSQL se pokusili zkr\u00e1tit dobu odezvy dotaz\u016f benchmarku TPC-H. St\u00e1hn\u011bte benchmark a <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">p\u0159izp\u016fsobte ho PostgreSQL<\/a><\/noindex>. Toto je neofici\u00e1ln\u00ed pou\u017eit\u00ed benchmarku TPC-H \u2014 ne pro porovn\u00e1n\u00ed datab\u00e1z\u00ed nebo hardwaru.<\/p>\n<p><\/p>\n<ol>\n<li>St\u00e1hn\u011bte si TPC-H_Tools_v2.17.3.zip (nebo nov\u011bj\u0161\u00ed verzi) <noindex><a rel=\"nofollow\" href=\"http:\/\/www.tpc.org\/tpc_documents_current_versions\/current_specifications.asp\">z ofici\u00e1ln\u00edch str\u00e1nek TPC<\/a><\/noindex>.<\/li>\n<li>P\u0159ejmenujte makefile.suite na Makefile a zm\u011b\u0148te ho, jak je pops\u00e1no zde: <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">https:\/\/github.com\/tvondra\/pg_tpch <\/a><\/noindex>. Zkompilujte k\u00f3d p\u0159\u00edkazem make.<\/li>\n<li>Vygenerujte data: <code>.\\\/dbgen -s 10<\/code> vytvo\u0159\u00ed datab\u00e1zi o velikosti 23 GB. To je dostate\u010dn\u00e9 pro pozorov\u00e1n\u00ed rozd\u00edlu ve v\u00fdkonu paraleln\u00edch a nep\u0159 Paraleln\u00ed dotaz\u016f.<\/li>\n<li>P\u0159eve\u010fte soubory <code>tbl<\/code> v <code>csv s for<\/code> a <code>sed<\/code>.<\/li>\n<li>Naklonujte repozit\u00e1\u0159 <code>pg_tpch<\/code> a zkop\u00edrujte soubory <code>csv<\/code> v <code>pg_tpch\\\/dss\\\/data<\/code>.<\/li>\n<li>Vytvo\u0159te dotazy p\u0159\u00edkazem <code>qgen<\/code>.<\/li>\n<li>Na\u010dt\u011bte data do datab\u00e1ze p\u0159\u00edkazem <code>.\\\/tpch.sh<\/code>.<\/li>\n<\/ol>\n<p><\/p>\n<h3 id=\"parallelnoe-posledovatelnoe-skanirovanie\">Paraleln\u00ed sekven\u010dn\u00ed skenov\u00e1n\u00ed<\/h3>\n<p><\/p>\n<p>M\u016f\u017ee b\u00fdt rychlej\u0161\u00ed ne d\u00edky paraleln\u00edmu \u010dten\u00ed, ale proto\u017ee jsou data rozlo\u017eena na v\u00edce j\u00e1drech CPU. V modern\u00edch OS jsou soubory dat PostgreSQL dob\u0159e ukl\u00e1d\u00e1ny do mezipam\u011bti. P\u0159edb\u011b\u017en\u00fdm \u010dten\u00edm lze z\u00edskat z \u00falo\u017ei\u0161t\u011b blok v\u011bt\u0161\u00ed, ne\u017e kolik po\u017eaduje d\u00e9mon PG. Proto v\u00fdkon dotazu nen\u00ed omezen vstupy\/v\u00fdstupy disku. Spot\u0159ebov\u00e1v\u00e1 cykly CPU, aby:<\/p>\n<p><\/p>\n<ul>\n<li>\u010detl \u0159\u00e1dky po jedn\u00e9 ze str\u00e1nek tabulky;<\/li>\n<li>porovn\u00e1val hodnoty \u0159\u00e1dk\u016f a podm\u00ednky <code>nen\u00ed spolehliv\u00fd:<\/code>.<\/li>\n<\/ul>\n<p><\/p>\n<p>Prove\u010fme jednoduch\u00fd dotaz <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;\nQUERY PLAN\n--------------------------------------------------------------------------------------------------------------------------\nSeq Scan on lineitem (cost=0.00..1964772.00 rows=58856235 width=5) (actual time=0.014..16951.669 rows=58839715 loops=1)\nFilter: (l_shipdate &lt;= &#039;1998-08-18 00:00:00&#039;::timestamp without time zone)\nRows Removed by Filter: 1146337\nPlanning Time: 0.203 ms\nExecution Time: 19035.100 ms<\/code><\/pre>\n<p><\/p>\n<p>Sekven\u010dn\u00ed skenov\u00e1n\u00ed d\u00e1v\u00e1 p\u0159\u00edli\u0161 mnoho \u0159\u00e1dk\u016f bez agregace, tak\u017ee dotaz je prov\u00e1d\u011bn jedn\u00edm j\u00e1drem CPU.<\/p>\n<p><\/p>\n<p>Pokud p\u0159id\u00e1me <code>SUM()<\/code>, je vid\u011bt, \u017ee dva pracovn\u00ed procesy pomohou urychlit dotaz:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">explain analyze select sum(l_quantity) as sum_qty from lineitem where l_shipdate  Gather (cost=1589701.91..1589702.12 rows=2 width=32) (actual time=8553.241..8555.067 rows=3 loops=1)\nWorkers Planned: 2\nWorkers Launched: 2\n-&gt; Partial Aggregate (cost=1588701.91..1588701.92 rows=1 width=32) (actual time=8547.546..8547.546 rows=1 loops=3)\n-&gt; Parallel Seq Scan on lineitem (cost=0.00..1527393.33 rows=24523431 width=5) (actual time=0.038..5998.417 rows=19613238 loops=3)\nFilter: (l_shipdate &lt;= &#039;1998-08-18 00:00:00&#039;::timestamp without time zone)\nRows Removed by Filter: 382112\nPlanning Time: 0.241 ms\nExecution Time: 8555.131 ms<\/code><\/pre>\n<p><\/p>\n<h3 id=\"parallelnaya-agregaciya\">Paraleln\u00ed agregace<\/h3>\n<p><\/p>\n<p>Uzlu \u201eParallel Seq Scan\u201c vytv\u00e1\u0159\u00ed \u0159\u00e1dky pro \u010d\u00e1ste\u010dnou agregaci. Uzlu \u201ePartial Aggregate\u201c zpracov\u00e1v\u00e1 tyto \u0159\u00e1dky pomoc\u00ed <code>SUM()<\/code>. Na konci ka\u017ed\u00fd SUM po\u010d\u00edtadlo ze v\u0161ech pracovn\u00edch proces\u016f je shrom\u00e1\u017ed\u011bno uzlem \u201eGather\u201c.<\/p>\n<p><\/p>\n<p>Kone\u010dn\u00fd v\u00fdsledek je vypo\u010d\u00edt\u00e1n uzlem \u201eFinalize Aggregate\u201c. Pokud m\u00e1te sv\u00e9 vlastn\u00ed agrega\u010dn\u00ed funkce, nezapome\u0148te je ozna\u010dit jako \u201eparallel safe\u201c.<\/p>\n<p><\/p>\n<h3 id=\"kolichestvo-rabochih-processov\">Po\u010det pracovn\u00edch proces\u016f<\/h3>\n<p><\/p>\n<p>Po\u010det pracovn\u00edch proces\u016f lze zv\u00fd\u0161it bez restartov\u00e1n\u00ed serveru:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">explain analyze select sum(l_quantity) as sum_qty from lineitem where l_shipdate  Gather (cost=1589701.91..1589702.12 rows=2 width=32) (actual time=8553.241..8555.067 rows=3 loops=1)\nWorkers Planned: 2\nWorkers Launched: 2\n-&gt; Partial Aggregate (cost=1588701.91..1588701.92 rows=1 width=32) (actual time=8547.546..8547.546 rows=1 loops=3)\n-&gt; Parallel Seq Scan on lineitem (cost=0.00..1527393.33 rows=24523431 width=5) (actual time=0.038..5998.417 rows=19613238 loops=3)\nFilter: (l_shipdate &lt;= &#039;1998-08-18 00:00:00&#039;::timestamp without time zone)\nRows Removed by Filter: 382112\nPlanning Time: 0.241 ms\nExecution Time: 8555.131 ms<\/code><\/pre>\n<p><\/p>\n<p>Co se zde d\u011bje? Po\u010det pracovn\u00edch proces\u016f se zdvojn\u00e1sobil a dotaz se zrychlil pouze 1,6599kr\u00e1t. V\u00fdpo\u010dty jsou zaj\u00edmav\u00e9. M\u011bli jsme 2 pracovn\u00ed procesy a 1 vedouc\u00ed. Po zm\u011bn\u011b m\u00e1me 4+1.<\/p>\n<p><\/p>\n<p>Na\u0161e maxim\u00e1ln\u00ed zrychlen\u00ed d\u00edky paraleln\u00edmu zpracov\u00e1n\u00ed: 5\/3 = 1,66(6)kr\u00e1t.<\/p>\n<p><\/p>\n<h2 id=\"kak-eto-rabotaet\">Jak to funguje?<\/h2>\n<p><\/p>\n<h3 id=\"processy\">Procesy<\/h3>\n<p><\/p>\n<p>Zpracov\u00e1n\u00ed dotazu v\u017edy za\u010d\u00edn\u00e1 vedouc\u00edm procesem. Vedouc\u00ed prov\u00e1d\u00ed ve\u0161ker\u00e9 nepohodln\u00e9 a \u010d\u00e1st paraleln\u00edho zpracov\u00e1n\u00ed. Ostatn\u00ed procesy, kter\u00e9 vykon\u00e1vaj\u00ed stejn\u00e9 dotazy, se naz\u00fdvaj\u00ed pracovn\u00edmi procesy. Paraleln\u00ed zpracov\u00e1n\u00ed vyu\u017e\u00edv\u00e1 infrastrukturu <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/bgworker.html\">dynamick\u00fdch pozad\u00ed pracovn\u00edch proces\u016f<\/a><\/noindex> (od verze 9.4). Jeliko\u017e jin\u00e9 \u010d\u00e1sti PostgreSQL pou\u017e\u00edvaj\u00ed procesy, a nikoli vl\u00e1kna, dotaz se 3 pracovn\u00edmi procesy mohl b\u00fdt 4kr\u00e1t rychlej\u0161\u00ed ne\u017e tradi\u010dn\u00ed zpracov\u00e1n\u00ed.<\/p>\n<p><\/p>\n<h3 id=\"vzaimodeystvie\">Interakce<\/h3>\n<p><\/p>\n<p>Pracovn\u00ed procesy komunikuj\u00ed s vedouc\u00edm pomoc\u00ed fronty zpr\u00e1v (na z\u00e1klad\u011b sd\u00edlen\u00e9 pam\u011bti). Ka\u017ed\u00fd proces m\u00e1 2 fronty: na chyby a na tupl\u00edky.<\/p>\n<p><\/p>\n<h3 id=\"skolko-nuzhno-rabochih-processov\">Kolik pracovn\u00edch proces\u016f je pot\u0159eba?<\/h3>\n<p><\/p>\n<p>Minim\u00e1ln\u00ed limit ur\u010duje parametr <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>. Pak prov\u00e1d\u011bc\u00ed proces dotaz\u016f bere pracovn\u00ed procesy z baz\u00e9nu, kter\u00fd je omezen parametrem <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>. Posledn\u00ed limit je <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>, tedy celkov\u00fd po\u010det pozad\u00ed proces\u016f.<\/p>\n<p><\/p>\n<p>Pokud se pracovn\u00ed proces nepoda\u0159\u00ed p\u0159id\u011blit, zpracov\u00e1n\u00ed bude jednoprocesn\u00ed.<\/p>\n<p><\/p>\n<p>Pl\u00e1nova\u010d dotaz\u016f m\u016f\u017ee sn\u00ed\u017eit pracovn\u00ed procesy na z\u00e1klad\u011b velikosti tabulky nebo indexu. K tomu existuj\u00ed parametry <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> a <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 tabulka =&gt; 1 pracovn\u00edk\n24MB tabulka =&gt; 2 pracovn\u00edci\n72MB tabulka =&gt; 3 pracovn\u00edci\nx =&gt; log(x \/ min_parallel_table_scan_size) \/ log(3) + 1 pracovn\u00edk<\/code><\/pre>\n<p><\/p>\n<p>Ka\u017ed\u00fdkr\u00e1t, kdy\u017e je tabulka 3kr\u00e1t v\u011bt\u0161\u00ed ne\u017e <code>min_parallel_(index|table)_scan_size<\/code>, Postgres p\u0159id\u00e1v\u00e1 pracovn\u00ed proces. Po\u010det pracovn\u00edch proces\u016f nen\u00ed zalo\u017een na n\u00e1kladech. Cyklov\u00e1 z\u00e1vislost zt\u011b\u017euje slo\u017eit\u00e9 implementace. M\u00edsto toho pl\u00e1nova\u010d pou\u017e\u00edv\u00e1 jednoduch\u00e1 pravidla.<\/p>\n<p><\/p>\n<p>V praxi tato pravidla nev\u017edy vyhovuj\u00ed produk\u010dn\u00edmu prost\u0159ed\u00ed, tak\u017ee je mo\u017en\u00e9 zm\u011bnit po\u010det pracovn\u00edch proces\u016f pro konkr\u00e9tn\u00ed tabulku: ALTER TABLE \u2026 SET (<code>parallel_workers = N<\/code>).<\/p>\n<p><\/p>\n<h3 id=\"pochemu-parallelnaya-obrabotka-ne-ispolzuetsya\">Pro\u010d se paraleln\u00ed zpracov\u00e1n\u00ed nepou\u017e\u00edv\u00e1?<\/h3>\n<p><\/p>\n<p>Krom\u011b dlouh\u00e9ho seznamu omezen\u00ed existuj\u00ed tak\u00e9 n\u00e1klady na kontrolu:<\/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 aby se p\u0159ede\u0161lo paraleln\u00edmu zpracov\u00e1n\u00ed kr\u00e1tk\u00fdch dotaz\u016f. Tento parametr odhaduje \u010das pot\u0159ebn\u00fd na p\u0159\u00edpravu pam\u011bti, spu\u0161t\u011bn\u00ed procesu a po\u010d\u00e1te\u010dn\u00ed v\u00fdm\u011bnu dat.<\/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>: komunikace vedouc\u00edho s pracovn\u00edmi procesy se m\u016f\u017ee prot\u00e1hnout v pom\u011bru k po\u010dtu tuple od pracovn\u00edch proces\u016f. Tento parametr po\u010d\u00edt\u00e1 n\u00e1klady na v\u00fdm\u011bnu dat.<\/p>\n<p><\/p>\n<h3 id=\"soedineniya-vlozhennyh-ciklov--nested-loop-join\">Spojen\u00ed vno\u0159en\u00fdch cykl\u016f \u2014 Nested Loop Join<\/h3>\n<p><\/p>\n<pre><code class=\"plaintext\">PostgreSQL 9.6+ m\u016f\u017ee vykon\u00e1vat vno\u0159en\u00e9 cykly paraleln\u011b \u2014 je to jednoduch\u00e1 operace.\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>Sb\u011br prob\u00edh\u00e1 na posledn\u00edm kroku, tak\u017ee Nested Loop Left Join \u2014 to je paraleln\u00ed operace. Paraleln\u00ed Index Only Scan byl zaveden a\u017e ve verzi 10. Funguje podobn\u011b jako paraleln\u00ed sekven\u010dn\u00ed skenov\u00e1n\u00ed. Podm\u00ednka <code>c_custkey = o_custkey<\/code> \u010dte jeden p\u0159\u00edkaz pro ka\u017ed\u00fd z\u00e1kaznick\u00fd \u0159\u00e1dek. Tak\u017ee nen\u00ed paraleln\u00ed.<\/p>\n<p><\/p>\n<h3 id=\"hesh-soedinenie--hash-join\">Hash Join \u2014 Hash Join<\/h3>\n<p><\/p>\n<p>Ka\u017ed\u00fd pracovn\u00ed proces vytv\u00e1\u0159\u00ed svou vlastn\u00ed hash tabulku do PostgreSQL 11. A pokud je t\u011bchto proces\u016f v\u00edce ne\u017e \u010dty\u0159i, v\u00fdkon se nezv\u00fd\u0161\u00ed. V nov\u00e9 verzi je hash tabulka spole\u010dn\u00e1. Ka\u017ed\u00fd pracovn\u00ed proces m\u016f\u017ee pou\u017e\u00edt WORK_MEM k vytvo\u0159en\u00ed hash tabulky.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">vyberte\n        l_shipmode,\n        sou\u010det(p\u0159\u00edpad\n                kdy\u017e o_orderpriority = '1-URGENT'\n                        nebo o_orderpriority = '2-HIGH'\n                        pak 1\n                jinak 0\n        end) jako high_line_count,\n        sou\u010det(p\u0159\u00edpad\n                kdy\u017e o_orderpriority  '1-URGENT'\n                        a o_orderpriority  '2-HIGH'\n                        pak 1\n                jinak 0\n        end) jako low_line_count\nz\n        orders,\n        lineitem\nkde\n        o_orderkey = l_orderkey\n        a l_shipmode v ('MAIL', 'AIR')\n        a l_commitdate &lt; l_receiptdate\n        a l_shipdate = datum '1996-01-01'\n        a l_receiptdate &lt; datum &#039;1996-01-01&#039; + interval &#039;1&#039; rok\ngrupovat podle\n        l_shipmode\n\u0159adit podle\n        l_shipmode\nOMEZEN\u00cd 1;\n                                                                                                                                    PL\u00c1N DOTAZU\n-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n OMEZEN\u00cd  (cena=1964755.66..1964961.44 \u0159\u00e1dk\u016f=1 \u0161\u00ed\u0159ka=27) (skute\u010dn\u00fd \u010das=7579.592..7922.997 \u0159\u00e1dk\u016f=1 smy\u010dky=1)\n   -&gt;  Z\u00e1v\u011bre\u010dn\u00e1 skupinov\u00e1 agregace  (cena=1964755.66..1966196.11 \u0159\u00e1dk\u016f=7 \u0161\u00ed\u0159ka=27) (skute\u010dn\u00fd \u010das=7579.590..7579.591 \u0159\u00e1dk\u016f=1 smy\u010dky=1)\n         Kl\u00ed\u010d skupiny: lineitem.l_shipmode\n         -&gt;  Shrom\u00e1\u017ed\u011bn\u00ed spojen\u00ed  (cena=1964755.66..1966195.83 \u0159\u00e1dk\u016f=28 \u0161\u00ed\u0159ka=27) (skute\u010dn\u00fd \u010das=7559.593..7922.319 \u0159\u00e1dk\u016f=6 smy\u010dky=1)\n               Pl\u00e1novan\u00e9 pracovn\u00edky: 4\n               Spu\u0161t\u011bn\u00e9 pracovn\u00edky: 4\n               -&gt;  \u010c\u00e1ste\u010dn\u00e1 skupinov\u00e1 agregace  (cena=1963755.61..1965192.44 \u0159\u00e1dk\u016f=7 \u0161\u00ed\u0159ka=27) (skute\u010dn\u00fd \u010das=7548.103..7564.592 \u0159\u00e1dk\u016f=2 smy\u010dky=5)\n                     Kl\u00ed\u010d skupiny: lineitem.l_shipmode\n                     -&gt;  \u0158azen\u00ed  (cena=1963755.61..1963935.20 \u0159\u00e1dk\u016f=71838 \u0161\u00ed\u0159ka=27) (skute\u010dn\u00fd \u010das=7530.280..7539.688 \u0159\u00e1dk\u016f=62519 smy\u010dky=5)\n                           Kl\u00ed\u010d pro \u0159azen\u00ed: lineitem.l_shipmode\n                           Metoda \u0159azen\u00ed: extern\u00ed slou\u010den\u00ed  Disk: 2304kB\n                           Pracovn\u00edk 0:  Metoda \u0159azen\u00ed: extern\u00ed slou\u010den\u00ed  Disk: 2064kB\n                           Pracovn\u00edk 1:  Metoda \u0159azen\u00ed: extern\u00ed slou\u010den\u00ed  Disk: 2384kB\n                           Pracovn\u00edk 2:  Metoda \u0159azen\u00ed: extern\u00ed slou\u010den\u00ed  Disk: 2264kB\n                           Pracovn\u00edk 3:  Metoda \u0159azen\u00ed: extern\u00ed slou\u010den\u00ed  Disk: 2336kB\n                           -&gt;  Paraleln\u00ed hash spojen\u00ed  (cena=382571.01..1957960.99 \u0159\u00e1dk\u016f=71838 \u0161\u00ed\u0159ka=27) (skute\u010dn\u00fd \u010das=7036.917..7499.692 \u0159\u00e1dk\u016f=62519 smy\u010dky=5)\n                                 Podm\u00ednka hash: (lineitem.l_orderkey = orders.o_orderkey)\n                                 -&gt;  Paraleln\u00ed sekven\u010dn\u00ed skenov\u00e1n\u00ed na lineitem  (cena=0.00..1552386.40 \u0159\u00e1dk\u016f=71838 \u0161\u00ed\u0159ka=19) (skute\u010dn\u00fd \u010das=0.583..4901.063 \u0159\u00e1dk\u016f=62519 smy\u010dky=5)\n                                       Filtr: ((l_shipmode = JAK\u00ddKOLI (&#039;{MAIL,AIR}&#039;::bpchar[])) A (l_commitdate &lt; l_receiptdate) A (l_shipdate = '1996-01-01'::datum) A (l_receiptdate &lt; &#039;1997-01-01 00:00:00&#039;::\u010das bez \u010dasov\u00e9ho p\u00e1sma))\n                                       Odebran\u00e9 \u0159\u00e1dky filtrem: 11934691\n                                 -&gt;  Paraleln\u00ed hash  (cena=313722.45..313722.45 \u0159\u00e1dk\u016f=3750045 \u0161\u00ed\u0159ka=20) (skute\u010dn\u00fd \u010das=2011.518..2011.518 \u0159\u00e1dk\u016f=3000000 smy\u010dky=5)\n                                       Ko\u0161e: 65536  D\u00e1vky: 256  Pou\u017eit\u00ed pam\u011bti: 3840kB\n                                       -&gt;  Paraleln\u00ed sekven\u010dn\u00ed skenov\u00e1n\u00ed na orders  (cena=0.00..313722.45 \u0159\u00e1dk\u016f=3750045 \u0161\u00ed\u0159ka=20) (skute\u010dn\u00fd \u010das=0.029..995.948 \u0159\u00e1dk\u016f=3000000 smy\u010dky=5)\n \u010cas pl\u00e1nov\u00e1n\u00ed: 0.977 ms\n \u010cas prov\u00e1d\u011bn\u00ed: 7923.770 ms<\/code><\/pre>\n<p><\/p>\n<p>Dotaz 12 z TPC-H n\u00e1zorn\u011b ukazuje paraleln\u00ed hash spojen\u00ed. Ka\u017ed\u00fd pracovn\u00ed proces se pod\u00edl\u00ed na vytv\u00e1\u0159en\u00ed spole\u010dn\u00e9 hash tabulky.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-sliyaniem--merge-join\">Slou\u010den\u00ed \u2014 Merge Join<\/h3>\n<p><\/p>\n<p>Slou\u010den\u00ed je z pohledu paralelnosti nep\u00e1rn\u00e9. Nebojte se, pokud je to posledn\u00ed f\u00e1ze dotazu, st\u00e1le m\u016f\u017ee b\u00fdt vykon\u00e1v\u00e1na paraleln\u011b.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">-- Dotaz 2 z TPC-H\nvysv\u011btlit (n&aacute;klady vypnuto) vybrat s_acctbal, s_name, n_name, p_partkey, p_mfgr, s_address, s_phone, s_comment\nz     part, supplier, partsupp, nation, region\nkde\n        p_partkey = ps_partkey\n        a s_suppkey = ps_suppkey\n        a p_size = 36\n        a p_type jako &#039;%BRASS&#039;\n        a s_nationkey = n_nationkey\n        a n_regionkey = r_regionkey\n        a r_name = &#039;AMERIKA&#039;\n        a ps_supplycost = (\n                vybrat\n                        min(ps_supplycost)\n                z     partsupp, supplier, nation, region\n                kde\n                        p_partkey = ps_partkey\n                        a s_suppkey = ps_suppkey\n                        a s_nationkey = n_nationkey\n                        a n_regionkey = r_regionkey\n                        a r_name = &#039;AMERIKA&#039;\n        )\n\u0159adit podle s_acctbal sestupn\u011b, n_name, s_name, p_partkey\nOMEZIT 100;\n                                                PL&Aacute;N DOTAZU\n----------------------------------------------------------------------------------------------------------\n OMEZIT\n   -&amp;gt;  \u0158adit\n         Kl&iacute;\u010d pro \u0159azen&iacute;: supplier.s_acctbal DESC, nation.n_name, supplier.s_name, part.p_partkey\n         -&amp;gt;  Slou\u010dit spojen&iacute;\n               Podm&iacute;nka slou\u010den&iacute;: (part.p_partkey = partsupp.ps_partkey)\n               Filtr spojen&iacute;: (partsupp.ps_supplycost = (Subpl&aacute;n 1))\n               -&amp;gt;  Sbrat s pomoc&iacute; shrom&aacute;\u017ed\u011bn&iacute;\n                     Pl&aacute;novan&iacute; pracovn&iacute;ci: 4\n                     -&amp;gt;  Paraleln&iacute; indexov&eacute; skenov&aacute;n&iacute; pomoc&iacute; &lt;strong&gt;part_pkey&lt;\/strong&gt; na part\n                           Filtr: (((p_type)::text ~~ &#039;%BRASS&#039;::text) A (p_size = 36))\n               -&amp;gt;  Materializovat\n                     -&amp;gt;  \u0158adit\n                           Kl&iacute;\u010d pro \u0159azen&iacute;: partsupp.ps_partkey\n                           -&amp;gt;  Vno\u0159en&aacute; smy\u010dka\n                                 -&amp;gt;  Vno\u0159en&aacute; smy\u010dka\n                                       Filtr spojen&iacute;: (nation.n_regionkey = region.r_regionkey)\n                                       -&amp;gt;  Sekven\u010dn&iacute; skenov&aacute;n&iacute; na region\n                                             Filtr: (r_name = &#039;AMERIKA&#039;::bpchar)\n                                       -&amp;gt;  Hashov&eacute; spojen&iacute;\n                                             Podm&iacute;nka hashe: (supplier.s_nationkey = nation.n_nationkey)\n                                             -&amp;gt;  Sekven\u010dn&iacute; skenov&aacute;n&iacute; na supplier\n                                             -&amp;gt;  Hashe\n                                                   -&amp;gt;  Sekven\u010dn&iacute; skenov&aacute;n&iacute; na nation\n                                 -&amp;gt;  Indexov&eacute; skenov&aacute;n&iacute; pomoc&iacute; idx_partsupp_suppkey na partsupp\n                                       Podm&iacute;nka indexu: (ps_suppkey = supplier.s_suppkey)\n               Subpl&aacute;n 1\n                 -&amp;gt;  Agregace\n                       -&amp;gt;  Vno\u0159en&aacute; smy\u010dka\n                             Filtr spojen&iacute;: (nation_1.n_regionkey = region_1.r_regionkey)\n                             -&amp;gt;  Sekven\u010dn&iacute; skenov&aacute;n&iacute; na region region_1\n                                   Filtr: (r_name = &#039;AMERIKA&#039;::bpchar)\n                             -&amp;gt;  Vno\u0159en&aacute; smy\u010dka\n                                   -&amp;gt;  Vno\u0159en&aacute; smy\u010dka\n                                         -&amp;gt;  Indexov&eacute; skenov&aacute;n&iacute; pomoc&iacute; idx_partsupp_partkey na partsupp partsupp_1\n                                               Podm&iacute;nka indexu: (part.p_partkey = ps_partkey)\n                                         -&amp;gt;  Indexov&eacute; skenov&aacute;n&iacute; pomoc&iacute; supplier_pkey na supplier supplier_1\n                                               Podm&iacute;nka indexu: (s_suppkey = partsupp_1.ps_suppkey)\n                                   -&amp;gt;  Indexov&eacute; skenov&aacute;n&iacute; pomoc&iacute; nation_pkey na nation nation_1\n                                         Podm&iacute;nka indexu: (n_nationkey = supplier_1.s_nationkey)<\/code><\/pre>\n<p><\/p>\n<p>Uzlu \u201eMerge Join\u201c je nad \u201eGather Merge\u201c. Tak\u017ee slou\u010den\u00ed nepou\u017e\u00edv\u00e1 paraleln\u00ed zpracov\u00e1n\u00ed. Ale uzlu \u201eParallel Index Scan\u201c po\u0159\u00e1d pom\u00e1h\u00e1 s segmentem. <code>part_pkey<\/code>.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-po-sekciyam\">Slou\u010den\u00ed podle odd\u00edl\u016f<\/h3>\n<p><\/p>\n<p>V PostgreSQL 11 <noindex><a rel=\"nofollow\" href=\"http:\/\/ashutoshpg.blogspot.com\/2017\/12\/partition-wise-joins-divide-and-conquer.html\">slou\u010den\u00ed podle odd\u00edl\u016f<\/a><\/noindex> je ve v\u00fdchoz\u00edm nastaven\u00ed vypnuto: m\u00e1 velmi n\u00e1kladn\u00e9 pl\u00e1nov\u00e1n\u00ed. Tabulky se podobn\u00fdm d\u011blen\u00edm lze slou\u010dit odd\u00edl po odd\u00edlu. Tak\u017ee Postgres vyu\u017eije men\u0161\u00ed hash tabulky. Ka\u017ed\u00e9 slou\u010den\u00ed odd\u00edl\u016f m\u016f\u017ee b\u00fdt paraleln\u00ed.<\/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                    PL\u00c1N DOTAZU\n---------------------------------------------------\n P\u0159ipojit\n   -&gt;  Hash Join\n         Hash Podm\u00ednka: (t2.b = t1.a)\n         -&gt;  Seq Scan na prt2_p1 t2\n               Filtrovat: ((b &gt;= 0) AND (b &lt;= 10000))\n         -&gt;  Hash\n               -&gt;  Seq Scan na prt1_p1 t1\n                     Filtrovat: (b = 0)\n   -&gt;  Hash Join\n         Hash Podm\u00ednka: (t2_1.b = t1_1.a)\n         -&gt;  Seq Scan na prt2_p2 t2_1\n               Filtrovat: ((b &gt;= 0) AND (b &lt;= 10000))\n         -&gt;  Hash\n               -&gt;  Seq Scan na prt1_p2 t1_1\n                     Filtrovat: (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                        PL\u00c1N DOTAZU\n-----------------------------------------------------------\n Shrom\u00e1\u017edit\n   Pl\u00e1novan\u00ed pracovn\u00edci: 4\n   -&gt;  Paraleln\u00ed P\u0159ipojit\n         -&gt;  Paraleln\u00ed Hash Join\n               Hash Podm\u00ednka: (t2_1.b = t1_1.a)\n               -&gt;  Paraleln\u00ed Seq Scan na prt2_p2 t2_1\n                     Filtrovat: ((b &gt;= 0) AND (b &lt;= 10000))\n               -&gt;  Paraleln\u00ed Hash\n                     -&gt;  Paraleln\u00ed Seq Scan na prt1_p2 t1_1\n                           Filtrovat: (b = 0)\n         -&gt;  Paraleln\u00ed Hash Join\n               Hash Podm\u00ednka: (t2.b = t1.a)\n               -&gt;  Paraleln\u00ed Seq Scan na prt2_p1 t2\n                     Filtrovat: ((b &gt;= 0) AND (b &lt;= 10000))\n               -&gt;  Paraleln\u00ed Hash\n                     -&gt;  Paraleln\u00ed Seq Scan na prt1_p1 t1\n                           Filtrovat: (b = 0)<\/code><\/pre>\n<p><\/p>\n<p>Hlavn\u00ed v\u011bc je, \u017ee slou\u010den\u00ed podle odd\u00edl\u016f je mo\u017en\u00e9 prov\u00e1d\u011bt paraleln\u011b, pouze pokud jsou tyto odd\u00edly dostate\u010dn\u011b velk\u00e9.<\/p>\n<p><\/p>\n<h3 id=\"parallelnoe-dopolnenie--parallel-append\">Paraleln\u00ed p\u0159id\u00e1n\u00ed \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> m\u016f\u017ee b\u00fdt pou\u017eito m\u00edsto r\u016fzn\u00fdch blok\u016f v r\u016fzn\u00fdch pracovn\u00edch procesech. Obvykle se vyskytuje u dotaz\u016f UNION ALL. Nev\u00fdhodou je m\u00e9n\u011b paralelismu, proto\u017ee ka\u017ed\u00fd pracovn\u00ed proces zpracov\u00e1v\u00e1 pouze 1 dotaz.<\/p>\n<p><\/p>\n<p>Zde byly spu\u0161t\u011bny 2 pracovn\u00ed procesy, p\u0159esto\u017ee bylo zapnuto 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   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\">Nejd\u016fle\u017eit\u011bj\u0161\u00ed prom\u011bnn\u00e9<\/h3>\n<p><\/p>\n<ul>\n<li>WORK_MEM omezuje mno\u017estv\u00ed pam\u011bti pro ka\u017ed\u00fd proces, nejen pro dotazy: work_mem <em> procesy <\/em> p\u0159ipojen\u00ed = velmi hodn\u011b pam\u011bti.<\/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 kolik pracovn\u00edch proces\u016f bude program pou\u017e\u00edvat pro paraleln\u00ed zpracov\u00e1n\u00ed podle pl\u00e1nu.<\/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 p\u0159izp\u016fsobuje celkov\u00fd po\u010det pracovn\u00edch proces\u016f po\u010dtu jader CPU na serveru.<\/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 tot\u00e9\u017e, ale pro paraleln\u00ed pracovn\u00ed procesy.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"itogi\">Z\u00e1v\u011bry<\/h3>\n<p><\/p>\n<p>Od verze 9.6 m\u016f\u017ee paraleln\u00ed zpracov\u00e1n\u00ed v\u00fdrazn\u011b zlep\u0161it v\u00fdkon slo\u017eit\u00fdch dotaz\u016f, kter\u00e9 skenuj\u00ed mnoho \u0159\u00e1dk\u016f nebo index\u016f. V PostgreSQL 10 je paraleln\u00ed zpracov\u00e1n\u00ed v\u00fdchoz\u00ed. Nezapome\u0148te jej vypnout na serverech s vysokou z\u00e1t\u011b\u017e\u00ed OLTP. Sekven\u010dn\u00ed skeny nebo skeny index\u016f spot\u0159ebov\u00e1vaj\u00ed velmi mnoho prost\u0159edk\u016f. Pokud nevytv\u00e1\u0159\u00edte zpr\u00e1vu pro cel\u00fd datov\u00fd soubor, dotazy lze u\u010dinit efektivn\u011bj\u0161\u00edmi jednodu\u0161e p\u0159id\u00e1n\u00edm chyb\u011bj\u00edc\u00edch index\u016f nebo pou\u017eit\u00edm spr\u00e1vn\u00e9 partitionace.<\/p>\n<p><\/p>\n<h3 id=\"ssylki\">Odkazy<\/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\">Paralelismus v PostgreSQL 11<\/a><\/noindex><\/li>\n<\/ul>\n<p>Zdroj: <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.3 - 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\/cs\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"cs_CZ\" \/>\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\/cs\/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\udd47Paraleln\u00ed dotazy v PostgreSQL | ProHoster","description":"V modern\u00edch CPU je mnoho jader.","canonical_url":"https:\/\/prohoster.info\/cs\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"cs_CZ","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\/cs\/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\/cs\/wp-json\/wp\/v2\/posts\/30900","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/comments?post=30900"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/posts\/30900\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/media\/22879"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/media?parent=30900"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/categories?post=30900"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/tags?post=30900"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}