{"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\/pl\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","title":{"rendered":"Zapytania r\u00f3wnoleg\u0142e w PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Zapytania r\u00f3wnoleg\u0142e w PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/04\/bbb4b4d3f8714bbdb9b26ada2f2253b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nW nowoczesnych procesorach jest wiele rdzeni. Przez lata aplikacje wysy\u0142a\u0142y zapytania do baz danych r\u00f3wnolegle. Je\u015bli jest to raportowe zapytanie do wielu wierszy w tabeli, wykonuje si\u0119 szybciej, gdy anga\u017cuje wiele rdzeni, a w PostgreSQL jest to mo\u017cliwe od wersji 9.6.<\/p>\n<p><\/p>\n<p>Zaj\u0119\u0142o to 3 lata, aby zrealizowa\u0107 funkcj\u0119 zapyta\u0144 r\u00f3wnoleg\u0142ych \u2014 trzeba by\u0142o przepisa\u0107 kod na r\u00f3\u017cnych etapach wykonywania zapyta\u0144. W PostgreSQL 9.6 pojawi\u0142a si\u0119 infrastruktura do dalszego ulepszania kodu. W kolejnych wersjach r\u00f3wnie\u017c inne typy zapyta\u0144 s\u0105 wykonywane r\u00f3wnolegle.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3 id=\"ogranicheniya\">Ograniczenia<\/h3>\n<p><\/p>\n<ul>\n<li>Nie w\u0142\u0105czaj r\u00f3wnoleg\u0142ego wykonywania, je\u015bli wszystkie rdzenie s\u0105 ju\u017c zaj\u0119te, w przeciwnym razie inne zapytania b\u0119d\u0105 spowalniane.<\/li>\n<li>Najwa\u017cniejsze, \u017ce r\u00f3wnoleg\u0142e przetwarzanie z wysokimi warto\u015bciami WORK_MEM zajmuje du\u017co pami\u0119ci \u2014 ka\u017cde po\u0142\u0105czenie haszowe lub sortowanie zajmuje pami\u0119\u0107 w obj\u0119to\u015bci work_mem.<\/li>\n<li>Zapytania OLTP o niskim op\u00f3\u017anieniu nie mog\u0105 by\u0107 przyspieszone przez r\u00f3wnoleg\u0142e wykonywanie. A je\u015bli zapytanie zwraca jeden wiersz, r\u00f3wnoleg\u0142e przetwarzanie tylko go spowolni.<\/li>\n<li>Programi\u015bci lubi\u0105 korzysta\u0107 z benchmarka TPC-H. Mo\u017ce masz podobne zapytania do idealnego r\u00f3wnoleg\u0142ego wykonywania.<\/li>\n<li>Tylko zapytania SELECT bez blokowania predykatami s\u0105 wykonywane r\u00f3wnolegle.<\/li>\n<li>Czasami odpowiednia indeksacja jest lepsza od sekwencyjnego skanowania tabeli w trybie r\u00f3wnoleg\u0142ym.<\/li>\n<li>Wstrzymywanie zapyta\u0144 i kursory nie s\u0105 obs\u0142ugiwane.<\/li>\n<li>Funkcje okienne i funkcje agreguj\u0105ce uporz\u0105dkowanych zbior\u00f3w nie s\u0105 r\u00f3wnoleg\u0142e.<\/li>\n<li>Nie zyskujesz nic w obci\u0105\u017ceniu wej\u015bcia-wyj\u015bcia.<\/li>\n<li>Nie ma r\u00f3wnoleg\u0142ych algorytm\u00f3w sortowania. Ale zapytania z sortowaniem mog\u0105 by\u0107 wykonywane r\u00f3wnolegle w niekt\u00f3rych aspektach.<\/li>\n<li>Zast\u0105p CTE (WITH \u2026) zagnie\u017cd\u017conym SELECT, aby w\u0142\u0105czy\u0107 r\u00f3wnoleg\u0142e przetwarzanie.<\/li>\n<li>Wrappery danych zewn\u0119trznych na razie nie obs\u0142uguj\u0105 r\u00f3wnoleg\u0142ego przetwarzania (a mog\u0142yby!).<\/li>\n<li>FULL OUTER JOIN nie jest obs\u0142ugiwany.<\/li>\n<li>max_rows wy\u0142\u0105cza r\u00f3wnoleg\u0142e przetwarzanie.<\/li>\n<li>Je\u015bli w zapytaniu jest funkcja, kt\u00f3ra nie jest oznaczona jako PARALLEL SAFE, zostanie wykonane w jednym w\u0105tku.<\/li>\n<li>Poziom izolacji transakcji SERIALIZABLE wy\u0142\u0105cza r\u00f3wnoleg\u0142e przetwarzanie.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"testovaya-sreda\">\u015arodowisko testowe<\/h3>\n<p><\/p>\n<p>Programi\u015bci PostgreSQL pr\u00f3bowali skr\u00f3ci\u0107 czas reakcji zapyta\u0144 z benchmarka TPC-H. Pobierz benchmark i <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">dostosuj go do PostgreSQL<\/a><\/noindex>. To nieoficjalne u\u017cycie benchmarku TPC-H \u2014 nie do por\u00f3wnywania baz danych ani sprz\u0119tu.<\/p>\n<p><\/p>\n<ol>\n<li>Pobierz TPC-H_Tools_v2.17.3.zip (lub nowsz\u0105 wersj\u0119) <noindex><a rel=\"nofollow\" href=\"http:\/\/www.tpc.org\/tpc_documents_current_versions\/current_specifications.asp\">z oficjalnej strony TPC<\/a><\/noindex>.<\/li>\n<li>Zmie\u0144 nazw\u0119 makefile.suite na Makefile i zmodyfikuj, jak opisano tutaj: <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">https:\/\/github.com\/tvondra\/pg_tpch <\/a><\/noindex>. Skompiluj kod poleceniem make.<\/li>\n<li>Wygeneruj dane: <code>.\\\/dbgen -s 10<\/code> tworzy baz\u0119 danych o wielko\u015bci 23 GB. To wystarczy, \u017ceby zobaczy\u0107 r\u00f3\u017cnic\u0119 w wydajno\u015bci zapyta\u0144 r\u00f3wnoleg\u0142ych i nier\u00f3wnoleg\u0142ych.<\/li>\n<li>Przekonwertuj pliki <code>tbl<\/code> do <code>csv za pomoc\u0105<\/code> i <code>sed<\/code>.<\/li>\n<li>Sklonuj repozytorium <code>pg_tpch<\/code> i skopiuj pliki <code>csv<\/code> do <code>pg_tpch\\\/dss\\\/data<\/code>.<\/li>\n<li>Utw\u00f3rz zapytania poleceniem <code>qgen<\/code>.<\/li>\n<li>Za\u0142aduj dane do bazy poleceniem <code>.\\\/tpch.sh<\/code>.<\/li>\n<\/ol>\n<p><\/p>\n<h3 id=\"parallelnoe-posledovatelnoe-skanirovanie\">R\u00f3wnoleg\u0142e sekwencyjne skanowanie<\/h3>\n<p><\/p>\n<p>Mo\u017ce by\u0107 szybsze nie przez r\u00f3wnoleg\u0142e odczyty, lecz dlatego, \u017ce dane s\u0105 rozproszone po wielu rdzeniach CPU. W nowoczesnych systemach operacyjnych pliki danych PostgreSQL s\u0105 dobrze buforowane. Dzi\u0119ki wst\u0119pnym odczytom mo\u017cna uzyska\u0107 z pami\u0119ci wi\u0119cej blok\u00f3w ni\u017c \u017c\u0105da demon PG. Dlatego wydajno\u015b\u0107 zapytania nie jest ograniczona przez dyskowe operacje wej\u015bcia-wyj\u015bcia. Wykorzystuje cykle CPU, aby:<\/p>\n<p><\/p>\n<ul>\n<li>czyta\u0107 linie jedna po drugiej z stron tabeli;<\/li>\n<li>por\u00f3wnywa\u0107 warto\u015bci wierszy i warunki <code>WHERE<\/code>.<\/li>\n<\/ul>\n<p><\/p>\n<p>Wykonaj proste zapytanie <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>Sekwencyjne skanowanie zwraca zbyt wiele wierszy bez agregacji, tak \u017ce zapytanie jest realizowane przez jeden rdze\u0144 CPU.<\/p>\n<p><\/p>\n<p>Je\u015bli dodasz <code>SUM()<\/code>, wida\u0107, \u017ce dwa procesy pomog\u0105 przyspieszy\u0107 zapytanie:<\/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; R\u00f3wnoleg\u0142e skanowanie sekwencyjne na 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\">R\u00f3wnoleg\u0142a agregacja<\/h3>\n<p><\/p>\n<p>W\u0119ze\u0142 &#171;Parallel Seq Scan&#187; generuje wiersze do cz\u0119\u015bciowej agregacji. W\u0119ze\u0142 &#171;Partial Aggregate&#187; przycina te wiersze za pomoc\u0105 <code>SUM()<\/code>. Na ko\u0144cu licznik SUM z ka\u017cdego w\u0105tku jest zbierany przez w\u0119ze\u0142 &#171;Gather&#187;.<\/p>\n<p><\/p>\n<p>Ostateczny wynik jest obliczany przez w\u0119ze\u0142 &#171;Finalize Aggregate&#187;. Je\u015bli masz swoje w\u0142asne funkcje agregacji, nie zapomnij oznaczy\u0107 ich jako &#171;parallel safe&#187;.<\/p>\n<p><\/p>\n<h3 id=\"kolichestvo-rabochih-processov\">Liczba proces\u00f3w roboczych<\/h3>\n<p><\/p>\n<p>Liczb\u0119 proces\u00f3w roboczych mo\u017cna zwi\u0119kszy\u0107 bez ponownego uruchamiania serwera:<\/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; R\u00f3wnoleg\u0142e skanowanie sekwencyjne na 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 tu si\u0119 dzieje? Liczba proces\u00f3w roboczych wzros\u0142a dwukrotnie, a zapytanie sta\u0142o si\u0119 jedynie 1,6599 razy szybsze. Obliczenia s\u0105 interesuj\u0105ce. Mieli\u015bmy 2 procesy robocze i 1 lidera. Po zmianie mieli\u015bmy 4+1.<\/p>\n<p><\/p>\n<p>Nasze maksymalne przyspieszenie dzi\u0119ki przetwarzaniu r\u00f3wnoleg\u0142emu: 5\/3 = 1,66(6) razy.<\/p>\n<p><\/p>\n<h2 id=\"kak-eto-rabotaet\">Jak to dzia\u0142a?<\/h2>\n<p><\/p>\n<h3 id=\"processy\">Procesy<\/h3>\n<p><\/p>\n<p>Wykonanie zapytania zawsze zaczyna si\u0119 od procesu lidera. Lider wykonuje wszystkie operacje nieparalne oraz cz\u0119\u015b\u0107 przetwarzania r\u00f3wnoleg\u0142ego. Inne procesy, kt\u00f3re wykonuj\u0105 te same zapytania, nazywaj\u0105 si\u0119 procesami roboczymi. Przetwarzanie r\u00f3wnoleg\u0142e u\u017cywa infrastruktury <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/bgworker.html\">dynamicznych proces\u00f3w roboczych w tle<\/a><\/noindex> (od wersji 9.4). Poniewa\u017c inne cz\u0119\u015bci PostgreSQL korzystaj\u0105 z proces\u00f3w, a nie w\u0105tk\u00f3w, zapytanie z 3 procesami roboczymi mog\u0142o by\u0107 4 razy szybsze ni\u017c tradycyjne przetwarzanie.<\/p>\n<p><\/p>\n<h3 id=\"vzaimodeystvie\">Interakcja<\/h3>\n<p><\/p>\n<p>Procesy robocze komunikuj\u0105 si\u0119 z liderem za po\u015brednictwem kolejki wiadomo\u015bci (opartej na pami\u0119ci wsp\u00f3\u0142dzielonej). Ka\u017cdy proces ma 2 kolejki: jedn\u0105 do b\u0142\u0119d\u00f3w i jedn\u0105 do krotek.<\/p>\n<p><\/p>\n<h3 id=\"skolko-nuzhno-rabochih-processov\">Ile potrzebujesz proces\u00f3w roboczych?<\/h3>\n<p><\/p>\n<p>Minimalne ograniczenie ustawia 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>. Potem wykonawca zapyta\u0144 pobiera procesy robocze z puli, ograniczonej przez parametr <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>. Ostatnie ograniczenie to <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>, czyli ca\u0142kowita liczba proces\u00f3w w tle.<\/p>\n<p><\/p>\n<p>Je\u015bli nie uda si\u0119 przydzieli\u0107 procesu roboczego, przetwarzanie b\u0119dzie jednoprosesowe.<\/p>\n<p><\/p>\n<p>Planista zapyta\u0144 mo\u017ce zmniejszy\u0107 liczb\u0119 proces\u00f3w roboczych w zale\u017cno\u015bci od rozmiaru tabeli lub indeksu. Do tego s\u0105 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> i <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 tabela =&gt; 1 proces roboczy\n24MB tabela =&gt; 2 procesy robocze\n72MB tabela =&gt; 3 procesy robocze\nx =&gt; log(x \/ min_parallel_table_scan_size) \/ log(3) + 1 proces roboczy<\/code><\/pre>\n<p><\/p>\n<p>Za ka\u017cdym razem, gdy tabela jest 3 razy wi\u0119ksza ni\u017c <code>min_parallel_(index|table)_scan_size<\/code>, Postgres dodaje proces roboczy. Liczba proces\u00f3w roboczych nie opiera si\u0119 na kosztach. Cykliczne zale\u017cno\u015bci utrudniaj\u0105 skomplikowane realizacje. Zamiast tego planista stosuje proste zasady.<\/p>\n<p><\/p>\n<p>W praktyce te zasady nie zawsze sprawdzaj\u0105 si\u0119 w produkcji, dlatego mo\u017cna zmieni\u0107 liczb\u0119 proces\u00f3w roboczych dla konkretnej tabeli: ALTER TABLE \u2026 SET (<code>parallel_workers = N<\/code>).<\/p>\n<p><\/p>\n<h3 id=\"pochemu-parallelnaya-obrabotka-ne-ispolzuetsya\">Dlaczego nie u\u017cywa si\u0119 przetwarzania r\u00f3wnoleg\u0142ego?<\/h3>\n<p><\/p>\n<p>Opr\u00f3cz d\u0142ugiej listy ogranicze\u0144 istniej\u0105 r\u00f3wnie\u017c kontrole koszt\u00f3w:<\/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 unikn\u0105\u0107 przetwarzania r\u00f3wnoleg\u0142ego w przypadku kr\u00f3tkich zapyta\u0144. Ten parametr oszacowuje czas potrzebny na przygotowanie pami\u0119ci, uruchomienie procesu i pocz\u0105tkow\u0105 wymian\u0119 danych.<\/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>: komunikacja lidera z pracownikami mo\u017ce by\u0107 op\u00f3\u017aniona proporcjonalnie do liczby krotek od proces\u00f3w roboczych. Ten parametr oblicza koszty wymiany danych.<\/p>\n<p><\/p>\n<h3 id=\"soedineniya-vlozhennyh-ciklov--nested-loop-join\">Po\u0142\u0105czenia zagnie\u017cd\u017conych p\u0119tli \u2014 Nested Loop Join<\/h3>\n<p><\/p>\n<pre><code class=\"plaintext\">PostgreSQL 9.6+ mo\u017ce wykonywa\u0107 zagnie\u017cd\u017cone p\u0119tle r\u00f3wnolegle \u2014 to prosta operacja.\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>Agregacja odbywa si\u0119 na ostatnim etapie, wi\u0119c Nested Loop Left Join \u2014 to operacja r\u00f3wnoleg\u0142a. Parallel Index Only Scan pojawi\u0142 si\u0119 dopiero w wersji 10. Dzia\u0142a w podobny spos\u00f3b jak r\u00f3wnoleg\u0142e skanowanie sekwencyjne. Warunek <code>c_custkey = o_custkey<\/code> odczytuje jedno zam\u00f3wienie dla ka\u017cdego klienta. Tak wi\u0119c nie jest to r\u00f3wnoleg\u0142e.<\/p>\n<p><\/p>\n<h3 id=\"hesh-soedinenie--hash-join\">Hash join \u2014 Hash Join<\/h3>\n<p><\/p>\n<p>Ka\u017cdy proces roboczy tworzy swoj\u0105 tablic\u0119 haszuj\u0105c\u0105 do PostgreSQL 11. A je\u015bli tych proces\u00f3w jest wi\u0119cej ni\u017c cztery, wydajno\u015b\u0107 nie wzro\u015bnie. W nowej wersji tablica haszuj\u0105ca jest wsp\u00f3lna. Ka\u017cdy proces roboczy mo\u017ce u\u017cywa\u0107 WORK_MEM, aby utworzy\u0107 tablic\u0119 haszuj\u0105c\u0105.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">wybierz\n        l_shipmode,\n        suma(przypadek\n                gdy o_orderpriority = '1-URGENT'\n                        lub o_orderpriority = '2-HIGH'\n                        wtedy 1\n                w przeciwnym razie 0\n        ko\u0144cz) jako high_line_count,\n        suma(przypadek\n                gdy o_orderpriority  '1-URGENT'\n                        i o_orderpriority  '2-HIGH'\n                        wtedy 1\n                w przeciwnym razie 0\n        ko\u0144cz) jako low_line_count\nz\n        zam\u00f3wienia,\n        pozycja zam\u00f3wienia\ngdzie\n        o_orderkey = l_orderkey\n        i l_shipmode w ('MAIL', 'AIR')\n        i l_commitdate &lt; l_receiptdate\n        i l_shipdate = data '1996-01-01'\n        i l_receiptdate &lt; data &#039;1996-01-01&#039; + interwa\u0142 &#039;1&#039; rok\ngrupuj wed\u0142ug\n        l_shipmode\nzam\u00f3w wed\u0142ug\n        l_shipmode\nLIMIT 1;\n                                                                                                                                    PLAN ZAPYTANIA\n-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n Limit  (koszt=1964755.66..1964961.44 wiersze=1 szeroko\u015b\u0107=27) (rzeczywisty czas=7579.592..7922.997 wiersze=1 p\u0119tle=1)\n   -&gt;  Finalizuj Grup\u0119Agregat  (koszt=1964755.66..1966196.11 wiersze=7 szeroko\u015b\u0107=27) (rzeczywisty czas=7579.590..7579.591 wiersze=1 p\u0119tle=1)\n         Klucz grupy: lineitem.l_shipmode\n         -&gt;  Zgromad\u017a Merguj  (koszt=1964755.66..1966195.83 wiersze=28 szeroko\u015b\u0107=27) (rzeczywisty czas=7559.593..7922.319 wiersze=6 p\u0119tle=1)\n               Planowane pracownicy: 4\n               Uruchomieni pracownicy: 4\n               -&gt;  Cz\u0119\u015bciowy GrupujAgregat  (koszt=1963755.61..1965192.44 wiersze=7 szeroko\u015b\u0107=27) (rzeczywisty czas=7548.103..7564.592 wiersze=2 p\u0119tle=5)\n                     Klucz grupy: lineitem.l_shipmode\n                     -&gt;  Sortuj  (koszt=1963755.61..1963935.20 wiersze=71838 szeroko\u015b\u0107=27) (rzeczywisty czas=7530.280..7539.688 wiersze=62519 p\u0119tle=5)\n                           Klucz sortowania: lineitem.l_shipmode\n                           Metoda sortowania: zewn\u0119trzna scalanie  Dysk: 2304kB\n                           Pracownik 0:  Metoda sortowania: zewn\u0119trzna scalanie  Dysk: 2064kB\n                           Pracownik 1:  Metoda sortowania: zewn\u0119trzna scalanie  Dysk: 2384kB\n                           Pracownik 2:  Metoda sortowania: zewn\u0119trzna scalanie  Dysk: 2264kB\n                           Pracownik 3:  Metoda sortowania: zewn\u0119trzna scalanie  Dysk: 2336kB\n                           -&gt;  R\u00f3wnoleg\u0142e Haszowanie Do\u0142\u0105czenie  (koszt=382571.01..1957960.99 wiersze=71838 szeroko\u015b\u0107=27) (rzeczywisty czas=7036.917..7499.692 wiersze=62519 p\u0119tle=5)\n                                 Warunek haszowania: (lineitem.l_orderkey = orders.o_orderkey)\n                                 -&gt;  R\u00f3wnoleg\u0142e Przeszukiwanie sekwecyjnie na pozycjach  (koszt=0.00..1552386.40 wiersze=71838 szeroko\u015b\u0107=19) (rzeczywisty czas=0.583..4901.063 wiersze=62519 p\u0119tle=5)\n                                       Filtr: ((l_shipmode = ANY (&#039;{MAIL,AIR}&#039;::bpchar[])) AND (l_commitdate &lt; l_receiptdate) AND (l_shipdate = '1996-01-01'::data) AND (l_receiptdate &lt; &#039;1997-01-01 00:00:00&#039;::znacznik bez strefy czasowej))\n                                       Wiersze usuni\u0119te przez filtr: 11934691\n                                 -&gt;  R\u00f3wnoleg\u0142e Hasz  (koszt=313722.45..313722.45 wiersze=3750045 szeroko\u015b\u0107=20) (rzeczywisty czas=2011.518..2011.518 wiersze=3000000 p\u0119tle=5)\n                                       Kosze: 65536  Partii: 256  U\u017cycie pami\u0119ci: 3840kB\n                                       -&gt;  R\u00f3wnoleg\u0142e Przeszukiwanie sekwecyjnie na zam\u00f3wienia  (koszt=0.00..313722.45 wiersze=3750045 szeroko\u015b\u0107=20) (rzeczywisty czas=0.029..995.948 wiersze=3000000 p\u0119tle=5)\n Czas planowania: 0.977 ms\n Czas wykonania: 7923.770 ms<\/code><\/pre>\n<p><\/p>\n<p>Zapytanie 12 z TPC-H ilustruje r\u00f3wnoleg\u0142e po\u0142\u0105czenie haszowe. Ka\u017cdy proces uczestniczy w tworzeniu wsp\u00f3lnej tabeli haszowej.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-sliyaniem--merge-join\">Po\u0142\u0105czenie z\u0142\u0105czeniem \u2014 Merge Join<\/h3>\n<p><\/p>\n<p>Po\u0142\u0105czenie z\u0142\u0105czeniem jest z natury nieprzyspieszone. Nie martw si\u0119, je\u015bli to ostatni etap zapytania \u2014 nadal mo\u017ce by\u0107 realizowane r\u00f3wnolegle.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">-- Zapytanie 2 z TPC-H\nwyja\u015bnij (koszty wy\u0142\u0105czone) wybierz s_acctbal, s_name, n_name, p_partkey, p_mfgr, s_address, s_phone, s_comment\nz    part, supplier, partsupp, nation, region\ngdzie\n        p_partkey = ps_partkey\n        i s_suppkey = ps_suppkey\n        i p_size = 36\n        i p_type podobne &#039;%BRASS&#039;\n        i s_nationkey = n_nationkey\n        i n_regionkey = r_regionkey\n        i r_name = &#039;AMERICA&#039;\n        i ps_supplycost = (\n                wybierz\n                        min(ps_supplycost)\n                z    partsupp, supplier, nation, region\n                gdzie\n                        p_partkey = ps_partkey\n                        i s_suppkey = ps_suppkey\n                        i s_nationkey = n_nationkey\n                        i n_regionkey = r_regionkey\n                        i r_name = &#039;AMERICA&#039;\n        )\nkolejno\u015b\u0107 wed\u0142ug s_acctbal malej\u0105co, n_name, s_name, p_partkey\nLIMIT 100;\n                                                PLAN ZAPYTANIA\n----------------------------------------------------------------------------------------------------------\n Limit\n   -&amp;gt;  Sort\n         Klucz Sortowania: supplier.s_acctbal MALEJ\u0104CO, nation.n_name, supplier.s_name, part.p_partkey\n         -&amp;gt;  Po\u0142\u0105czenie Scalaj\u0105ce\n               Warunek Scalania: (part.p_partkey = partsupp.ps_partkey)\n               Filtr Po\u0142\u0105czenia: (partsupp.ps_supplycost = (SubPlan 1))\n               -&amp;gt;  Scalanie Gromadz\u0105ce\n                     Zaplanowani pracownicy: 4\n                     -&amp;gt;  R&oacute;wnoleg\u0142e Skany Indeksu przy u\u017cyciu &lt;strong&gt;part_pkey&lt;\/strong&gt; na cz\u0119\u015bci\n                           Filtr: (((p_type)::text ~~ &#039;%BRASS&#039;::text) I (p_size = 36))\n               -&amp;gt;  Materializacja\n                     -&amp;gt;  Sort\n                           Klucz Sortowania: partsupp.ps_partkey\n                           -&amp;gt;  P\u0119tla Zagnie\u017cd\u017cona\n                                 -&amp;gt;  P\u0119tla Zagnie\u017cd\u017cona\n                                       Filtr Po\u0142\u0105czenia: (nation.n_regionkey = region.r_regionkey)\n                                       -&amp;gt;  Se kw scan na region\n                                             Filtr: (r_name = &#039;AMERICA&#039;::bpchar)\n                                       -&amp;gt;  Po\u0142\u0105czenie Haszowe\n                                             Warunek Haszowy: (supplier.s_nationkey = nation.n_nationkey)\n                                             -&amp;gt;  Seq Scan na supplier\n                                             -&amp;gt;  Hasz\n                                                   -&amp;gt;  Seq Scan na nation\n                                 -&amp;gt;  Scan Indeksu przy u\u017cyciu idx_partsupp_suppkey na partsupp\n                                       Warunek Indeksu: (ps_suppkey = supplier.s_suppkey)\n               SubPlan 1\n                 -&amp;gt;  Agregacja\n                       -&amp;gt;  P\u0119tla Zagnie\u017cd\u017cona\n                             Filtr Po\u0142\u0105czenia: (nation_1.n_regionkey = region_1.r_regionkey)\n                             -&amp;gt;  Seq Scan na region region_1\n                                   Filtr: (r_name = &#039;AMERICA&#039;::bpchar)\n                             -&amp;gt;  P\u0119tla Zagnie\u017cd\u017cona\n                                   -&amp;gt;  P\u0119tla Zagnie\u017cd\u017cona\n                                         -&amp;gt;  Scan Indeksu przy u\u017cyciu idx_partsupp_partkey na partsupp partsupp_1\n                                               Warunek Indeksu: (part.p_partkey = ps_partkey)\n                                         -&amp;gt;  Scan Indeksu przy u\u017cyciu supplier_pkey na supplier supplier_1\n                                               Warunek Indeksu: (s_suppkey = partsupp_1.ps_suppkey)\n                                   -&amp;gt;  Scan Indeksu przy u\u017cyciu nation_pkey na nation nation_1\n                                         Warunek Indeksu: (n_nationkey = supplier_1.s_nationkey)<\/code><\/pre>\n<p><\/p>\n<p>W\u0119ze\u0142 &#171;Merge Join&#187; znajduje si\u0119 nad &#171;Gather Merge&#187;. Tak wi\u0119c \u0142\u0105czenie nie wykorzystuje przetwarzania r\u00f3wnoleg\u0142ego. Ale w\u0119ze\u0142 &#171;Parallel Index Scan&#187; nadal pomaga w segmencie. <code>part_pkey<\/code>.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-po-sekciyam\">Po\u0142\u0105czenie wed\u0142ug sekcji<\/h3>\n<p><\/p>\n<p>W PostgreSQL 11 <noindex><a rel=\"nofollow\" href=\"http:\/\/ashutoshpg.blogspot.com\/2017\/12\/partition-wise-joins-divide-and-conquer.html\">po\u0142\u0105czenie wed\u0142ug sekcji<\/a><\/noindex> domy\u015blnie wy\u0142\u0105czone: ma bardzo kosztowne planowanie. Tabele o podobnym podzia\u0142ach mo\u017cna \u0142\u0105czy\u0107 sekcja po sekcji. W ten spos\u00f3b Postgres wykorzysta mniejsze tabele haszowe. Ka\u017cde po\u0142\u0105czenie sekcji mo\u017ce by\u0107 r\u00f3wnoleg\u0142e.<\/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 ZAPYTANIA\n---------------------------------------------------\n Dodaj\n   -&gt;  Z\u0142\u0105czenie haszowe\n         Warunek hasza: (t2.b = t1.a)\n         -&gt;  Skanowanie sekwencyjne na prt2_p1 t2\n               Filtr: ((b &gt;= 0) AND (b &lt;= 10000))\n         -&gt;  Hasz\n               -&gt;  Skanowanie sekwencyjne na prt1_p1 t1\n                     Filtr: (b = 0)\n   -&gt;  Z\u0142\u0105czenie haszowe\n         Warunek hasza: (t2_1.b = t1_1.a)\n         -&gt;  Skanowanie sekwencyjne na prt2_p2 t2_1\n               Filtr: ((b &gt;= 0) AND (b &lt;= 10000))\n         -&gt;  Hasz\n               -&gt;  Skanowanie sekwencyjne na prt1_p2 t1_1\n                     Filtr: (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 ZAPYTANIA\n-----------------------------------------------------------\n Zbierz\n   Zaplanowani pracownicy: 4\n   -&gt;  R\u00f3wnoleg\u0142y dodatek\n         -&gt;  R\u00f3wnoleg\u0142e z\u0142\u0105czenie haszowe\n               Warunek hasza: (t2_1.b = t1_1.a)\n               -&gt;  R\u00f3wnoleg\u0142e skanowanie sekwencyjne na prt2_p2 t2_1\n                     Filtr: ((b &gt;= 0) AND (b &lt;= 10000))\n               -&gt;  R\u00f3wnoleg\u0142y hasz\n                     -&gt;  R\u00f3wnoleg\u0142e skanowanie sekwencyjne na prt1_p2 t1_1\n                           Filtr: (b = 0)\n         -&gt;  R\u00f3wnoleg\u0142e z\u0142\u0105czenie haszowe\n               Warunek hasza: (t2.b = t1.a)\n               -&gt;  R\u00f3wnoleg\u0142e skanowanie sekwencyjne na prt2_p1 t2\n                     Filtr: ((b &gt;= 0) AND (b &lt;= 10000))\n               -&gt;  R\u00f3wnoleg\u0142y hasz\n                     -&gt;  R\u00f3wnoleg\u0142e skanowanie sekwencyjne na prt1_p1 t1\n                           Filtr: (b = 0)<\/code><\/pre>\n<p><\/p>\n<p>G\u0142\u00f3wna kwestia, po\u0142\u0105czenie wed\u0142ug sekcji mo\u017ce by\u0107 r\u00f3wnoleg\u0142e, tylko je\u015bli te sekcje s\u0105 wystarczaj\u0105co du\u017ce.<\/p>\n<p><\/p>\n<h3 id=\"parallelnoe-dopolnenie--parallel-append\">R\u00f3wnoleg\u0142y dodatek \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> mo\u017ce by\u0107 u\u017cywany zamiast r\u00f3\u017cnych blok\u00f3w w r\u00f3\u017cnych procesach roboczych. Zwykle jest to zwi\u0105zane z zapytaniami UNION ALL. Wad\u0105 jest mniejszy poziom r\u00f3wnoleg\u0142o\u015bci, poniewa\u017c ka\u017cdy proces roboczy przetwarza tylko 1 zapytanie.<\/p>\n<p><\/p>\n<p>Tutaj uruchomiono 2 procesy robocze, chocia\u017c w\u0142\u0105czono 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\">Najwa\u017cniejsze zmienne<\/h3>\n<p><\/p>\n<ul>\n<li>WORK_MEM ogranicza ilo\u015b\u0107 pami\u0119ci dla ka\u017cdego procesu, nie tylko dla zapyta\u0144: work_mem <em> procesy <\/em> po\u0142\u0105czenia = bardzo du\u017co pami\u0119ci.<\/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 ile proces\u00f3w roboczych program b\u0119dzie u\u017cywa\u0107 do r\u00f3wnoleg\u0142ego przetwarzania z planu.<\/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 dostosowuje og\u00f3ln\u0105 liczb\u0119 proces\u00f3w roboczych do liczby rdzeni CPU na serwerze.<\/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 to samo, ale dla r\u00f3wnoleg\u0142ych proces\u00f3w roboczych.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"itogi\">Podsumowanie<\/h3>\n<p><\/p>\n<p>Od wersji 9.6 r\u00f3wnoleg\u0142e przetwarzanie mo\u017ce znacznie poprawi\u0107 wydajno\u015b\u0107 skomplikowanych zapyta\u0144, kt\u00f3re skanuj\u0105 wiele wierszy lub indeks\u00f3w. W PostgreSQL 10 r\u00f3wnoleg\u0142e przetwarzanie jest domy\u015blnie w\u0142\u0105czone. Nie zapomnij wy\u0142\u0105czy\u0107 go na serwerach z du\u017cym obci\u0105\u017ceniem OLTP. Sekwencyjne skany lub skany indeks\u00f3w zu\u017cywaj\u0105 bardzo du\u017co zasob\u00f3w. Je\u015bli nie wykonujesz raportu na ca\u0142ym zestawie danych, zapytania mo\u017cna uczyni\u0107 bardziej efektywnymi, po prostu dodaj\u0105c brakuj\u0105ce indeksy lub korzystaj\u0105c z odpowiedniego partycjonowania.<\/p>\n<p><\/p>\n<h3 id=\"ssylki\">Linki<\/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\">R\u00f3wnoleg\u0142o\u015b\u0107 w PostgreSQL 11<\/a><\/noindex><\/li>\n<\/ul>\n<p>\u0179r\u00f3d\u0142o: <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.1.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\/pl\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"pl_PL\" \/>\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\/pl\/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\udd47R\u00f3wnoleg\u0142e zapytania w PostgreSQL | ProHoster","description":"Nowoczesne procesory maj\u0105 bardzo du\u017co rdzeni.","canonical_url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pl_PL","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\/pl\/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\/pl\/wp-json\/wp\/v2\/posts\/30900","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/comments?post=30900"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/30900\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/22879"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=30900"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=30900"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=30900"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}