{"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\/nl\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","title":{"rendered":"Parallelle aanvragen in PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Parallelle aanvragen in PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/04\/bbb4b4d3f8714bbdb9b26ada2f2253b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nModerne CPU's hebben veel kernen. Jarenlang hebben applicaties aanvragen parallel naar databases gestuurd. Als het gaat om een rapportaanvraag van meerdere rijen in een tabel, wordt deze sneller uitgevoerd wanneer meerdere CPU's zijn ingezet. In PostgreSQL is dit mogelijk sinds versie 9.6.<\/p>\n<p><\/p>\n<p>Het duurde 3 jaar om de functie voor parallelle aanvragen te implementeren \u2014 de code moest op verschillende momenten van de uitvoering van aanvragen herzien worden. PostgreSQL 9.6 introduceerde de infrastructuur voor verdere verbetering van de code. In latere versies kunnen ook andere typen aanvragen parallel worden uitgevoerd.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3 id=\"ogranicheniya\">Beperkingen<\/h3>\n<p><\/p>\n<ul>\n<li>Schakel parallelle uitvoering niet in als alle kernen al in gebruik zijn, anders zullen andere aanvragen traag worden.<\/li>\n<li>Het belangrijkste is dat parallelle verwerking met hoge waarden van WORK_MEM veel geheugen gebruikt \u2014 elke hash-verbinding of sortering neemt geheugen in beslag ter grootte van work_mem.<\/li>\n<li>OLTP-aanvragen met lage latentie kunnen niet versneld worden door parallelle uitvoering. En als een aanvraag \u00e9\u00e9n rij retourneert, vertraagt parallelle verwerking deze alleen maar.<\/li>\n<li>Ontwikkelaars houden ervan om de TPC-H benchmark te gebruiken. Misschien hebt u vergelijkbare aanvragen voor perfecte parallelle uitvoering.<\/li>\n<li>Alleen SELECT-aanvragen zonder predicatenblokkering worden parallel uitgevoerd.<\/li>\n<li>Soms is goede indexing beter dan sequenti\u00eble scanning van de tabel in parallelle modus.<\/li>\n<li>Het pauzeren van aanvragen en cursors wordt niet ondersteund.<\/li>\n<li>Raamfuncties en aggregatiefuncties van geordende sets zijn niet parallel.<\/li>\n<li>U wint niets in de invoer-uitvoer werkbelasting.<\/li>\n<li>Er zijn geen parallelle sorteeralgoritmen. Maar aanvragen met sorteringen kunnen in bepaalde aspecten parallel worden uitgevoerd.<\/li>\n<li>Vervang CTE (WITH \u2026) door een genestelde SELECT om parallelle verwerking mogelijk te maken.<\/li>\n<li>Wraps voor externe gegevens ondersteunen momenteel geen parallelle verwerking (wat ze zouden kunnen!).<\/li>\n<li>FULL OUTER JOIN wordt niet ondersteund.<\/li>\n<li>max_rows schakelt parallelle verwerking uit.<\/li>\n<li>Als er in een aanvraag een functie is die niet gemarkeerd is als PARALLEL SAFE, wordt deze enkelvoudig uitgevoerd.<\/li>\n<li>Het isolatieniveau van de transactie SERIALIZABLE schakelt parallelle verwerking uit.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"testovaya-sreda\">Testomgeving<\/h3>\n<p><\/p>\n<p>Ontwikkelaars van PostgreSQL hebben geprobeerd de responstijd van TPC-H benchmark aanvragen te verlagen. Download de benchmark en <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">pas deze aan voor PostgreSQL<\/a><\/noindex>. Dit is een niet-offici\u00eble gebruik van de TPC-H benchmark - niet voor het vergelijken van databases of hardware.<\/p>\n<p><\/p>\n<ol>\n<li>Download TPC-H_Tools_v2.17.3.zip (of een nieuwere versie) <noindex><a rel=\"nofollow\" href=\"http:\/\/www.tpc.org\/tpc_documents_current_versions\/current_specifications.asp\">van de TPC-website<\/a><\/noindex>.<\/li>\n<li>Hernoem makefile.suite naar Makefile en wijzig het zoals hier beschreven: <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">https:\/\/github.com\/tvondra\/pg_tpch <\/a><\/noindex>. Compileer de code met het commando make.<\/li>\n<li>Genereer gegevens: <code>.\\\/dbgen -s 10<\/code> maakt een database van 23 GB. Dit is voldoende om het verschil in prestaties van parallelle en niet-parallelle queries te zien.<\/li>\n<li>Converteer bestanden <code>tbl<\/code> in <code>csv met for<\/code> en <code>sed<\/code>.<\/li>\n<li>Clone de repository <code>pg_tpch<\/code> en kopieer de bestanden <code>csv<\/code> in <code>pg_tpch\\\/dss\\\/data<\/code>.<\/li>\n<li>Maak de queries met het commando <code>qgen<\/code>.<\/li>\n<li>Laad de gegevens in de database met het commando <code>.\\\/tpch.sh<\/code>.<\/li>\n<\/ol>\n<p><\/p>\n<h3 id=\"parallelnoe-posledovatelnoe-skanirovanie\">Parallel sequente scans<\/h3>\n<p><\/p>\n<p>Het kan sneller zijn, niet vanwege parallelle lezing, maar omdat de gegevens verspreid zijn over veel CPU-kernen. In moderne besturingssystemen worden PostgreSQL-gegevensbestanden goed gecached. Met vooruitlezing kan meer dan het door de PG-daemon aangevraagde blok uit de opslag worden gehaald. Daarom wordt de query-prestatie niet beperkt door schijfinvoer\/-uitvoer. Het verbruikt CPU-cycli om:<\/p>\n<p><\/p>\n<ul>\n<li>rijen \u00e9\u00e9n voor \u00e9\u00e9n te lezen van de tabelpagina's;<\/li>\n<li>waarden van rijen en voorwaarden te vergelijken <code>WAAR<\/code>.<\/li>\n<\/ul>\n<p><\/p>\n<p>Laten we een eenvoudige query uitvoeren <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 zonder tijdzone)\nRows Removed by Filter: 1146337\nPlanning Time: 0.203 ms\nExecution Time: 19035.100 ms<\/code><\/pre>\n<p><\/p>\n<p>Een sequenti\u00eble scan geeft te veel rijen zonder aggregatie, zodat de query met \u00e9\u00e9n CPU-kern wordt uitgevoerd.<\/p>\n<p><\/p>\n<p>Als we toevoegen <code>SUM()<\/code>, is het duidelijk dat twee werkprocessen de query zullen versnellen:<\/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)\nGeplande Werkers: 2\nGeluide Werkers: 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 op 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 zonder tijdzone)\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\">Parallel aggregatie<\/h3>\n<p><\/p>\n<p>De node &#171;Parallel Seq Scan&#187; genereert rijen voor gedeeltelijke aggregatie. De node &#171;Partial Aggregate&#187; snijdt deze rijen af met behulp van <code>SUM()<\/code>. Aan het einde verzamelt de SUM-teller van elk werkproces door de node &#171;Gather&#187;.<\/p>\n<p><\/p>\n<p>Het uiteindelijke resultaat wordt berekend door de node &#171;Finalize Aggregate&#187;. Als u eigen aggregatiefuncties heeft, vergeet dan niet om deze als &#171;parallel safe&#187; te markeren.<\/p>\n<p><\/p>\n<h3 id=\"kolichestvo-rabochih-processov\">Aantal werkprocessen<\/h3>\n<p><\/p>\n<p>Het aantal werkprocessen kan zonder de server opnieuw op te starten worden vergroot:<\/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)\nGeplande Werkers: 2\nGeluide Werkers: 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 op 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 zonder tijdzone)\nRows Removed by Filter: 382112\nPlanning Time: 0.241 ms\nExecution Time: 8555.131 ms<\/code><\/pre>\n<p><\/p>\n<p>Wat gebeurt hier? Het aantal werkprocessen is verdubbeld, en de query is slechts 1,6599 keer sneller geworden. De berekeningen zijn interessant. We hadden 2 werkprocessen en 1 leider. Na de wijziging zijn het er 4+1 geworden.<\/p>\n<p><\/p>\n<p>Onze maximale versnelling door parallelle verwerking: 5\/3 = 1,66(6) keer.<\/p>\n<p><\/p>\n<h2 id=\"kak-eto-rabotaet\">How does it work?<\/h2>\n<p><\/p>\n<h3 id=\"processy\">Processen<\/h3>\n<p><\/p>\n<p>De uitvoering van een query begint altijd met het leidende proces. De leider voert alles niet-parallel en een deel van de parallelle verwerking uit. Andere processen die dezelfde queries uitvoeren, worden werkprocessen genoemd. Parallelle verwerking maakt gebruik van de infrastructuur <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/bgworker.html\">dynamische achtergrondwerkprocessen<\/a><\/noindex> (sinds versie 9.4). Aangezien andere onderdelen van PostgreSQL processen in plaats van threads gebruiken, kon een query met 3 werkprocessen 4 keer sneller zijn dan conventionele verwerking.<\/p>\n<p><\/p>\n<h3 id=\"vzaimodeystvie\">Interacties<\/h3>\n<p><\/p>\n<p>Werkprocessen communiceren met de leider via een berichtenwachtrij (gebaseerd op gedeeld geheugen). Elk proces heeft 2 wachtrijen: voor fouten en voor tuples.<\/p>\n<p><\/p>\n<h3 id=\"skolko-nuzhno-rabochih-processov\">Hoeveel werkprocessen zijn nodig?<\/h3>\n<p><\/p>\n<p>De minimale beperking wordt ingesteld door de parameter <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>. Vervolgens haalt de query-uitvoerder werkprocessen uit de pool, die is beperkt door de parameter <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>. De laatste beperking is <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>, dat wil zeggen het totale aantal achtergrondprocessen.<\/p>\n<p><\/p>\n<p>Als er geen werkproces kan worden toegewezen, is de verwerking enkelvoudig.<\/p>\n<p><\/p>\n<p>De queryplanner kan het aantal werkprocessen verminderen op basis van de grootte van de tabel of index. Hiervoor zijn er de parameters <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> en <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 worker\n24MB tabel =&gt; 2 workers\n72MB tabel =&gt; 3 workers\nx =&gt; log(x \/ min_parallel_table_scan_size) \/ log(3) + 1 worker<\/code><\/pre>\n<p><\/p>\n<p>Elke keer dat een tabel 3 keer groter is dan <code>min_parallel_(index|table)_scan_size<\/code>, voegt Postgres een werkproces toe. Het aantal werkprocessen is niet gebaseerd op kosten. Circulaire afhankelijkheid bemoeilijkt complexe implementaties. In plaats daarvan gebruikt de planner eenvoudige regels.<\/p>\n<p><\/p>\n<p>In de praktijk zijn deze regels niet altijd geschikt voor productie, dus je kunt het aantal werkprocessen voor een specifieke tabel wijzigen: ALTER TABLE \u2026 SET (<code>parallel_workers = N<\/code>).<\/p>\n<p><\/p>\n<h3 id=\"pochemu-parallelnaya-obrabotka-ne-ispolzuetsya\">Waarom wordt parallele verwerking niet gebruikt?<\/h3>\n<p><\/p>\n<p>Naast de lange lijst met beperkingen zijn er ook kostencontroles:<\/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 om zonder parallele verwerking korte aanvragen af te handelen. Deze parameter schat de tijd voor geheugenv voorbereiding, processtart en initi\u00eble gegevensuitwisseling.<\/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>: de communicatie van de leider met de werkprocessen kan evenredig toenemen met het aantal tuples van de werkprocessen. Deze parameter berekent de kosten voor gegevensuitwisseling.<\/p>\n<p><\/p>\n<h3 id=\"soedineniya-vlozhennyh-ciklov--nested-loop-join\">Geneste lusverbindingen \u2014 Nested Loop Join<\/h3>\n<p><\/p>\n<pre><code class=\"plaintext\">PostgreSQL 9.6+ kan geneste lussen parallel uitvoeren \u2014 dit is een eenvoudige operatie.\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>De verzameling vindt plaats in de laatste fase, zodat de Nested Loop Left Join een parallelle bewerking is. Parallel Index Only Scan verscheen pas in versie 10. Het werkt op dezelfde manier als parallel sequentieel scannen. Voorwaarde <code>c_custkey = o_custkey<\/code> leest \u00e9\u00e9n bestelling voor elke klantregel. Het is dus niet parallel.<\/p>\n<p><\/p>\n<h3 id=\"hesh-soedinenie--hash-join\">Hash-verbinding \u2014 Hash Join<\/h3>\n<p><\/p>\n<p>Elke werkproces cre\u00ebert zijn eigen hash-tabel tot PostgreSQL 11. En als er meer dan vier van deze processen zijn, zal de prestaties niet toenemen. In de nieuwe versie is de hashtabel gemeenschappelijk. Elke werkproces kan WORK_MEM gebruiken om een hash-tabel te maken.<\/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>Query 12 van TPC-H toont duidelijk een parallel hash-verbinding. Elke werker draagt bij aan het cre\u00ebren van een gezamenlijke hashtabel.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-sliyaniem--merge-join\">Samenvoegen - Merge Join<\/h3>\n<p><\/p>\n<p>Samenvoegen is van nature niet parallel. Maak je geen zorgen als dit de laatste stap van de query is; het kan nog steeds parallel worden uitgevoerd.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">-- Query 2 van TPC-H\nexplain (kosten uit) 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;AMERIKA&#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;AMERIKA&#039;\n        )\norder by s_acctbal desc, n_name, s_name, p_partkey\nLIMIT 100;\n                                                QUERY PLAN\n----------------------------------------------------------------------------------------------------------\n Beperking\n   -&amp;gt;  Sorteer\n         Sorteer Sleutel: supplier.s_acctbal DESC, nation.n_name, supplier.s_name, part.p_partkey\n         -&amp;gt;  Samenvoegen\n               Samenvoeg Voorwaarde: (part.p_partkey = partsupp.ps_partkey)\n               Join Filter: (partsupp.ps_supplycost = (SubPlan 1))\n               -&amp;gt;  Verzamelen\n                     Werknemers Gepland: 4\n                     -&amp;gt;  Parallel Index Scan using &lt;strong&gt;part_pkey&lt;\/strong&gt; op part\n                           Filter: (((p_type)::text ~~ &#039;%BRASS&#039;::text) EN (p_size = 36))\n               -&amp;gt;  Materialiseren\n                     -&amp;gt;  Sorteer\n                           Sorteer Sleutel: partsupp.ps_partkey\n                           -&amp;gt;  Geneste Lus\n                                 -&amp;gt;  Geneste Lus\n                                       Join Filter: (nation.n_regionkey = region.r_regionkey)\n                                       -&amp;gt;  Seq Scan op region\n                                             Filter: (r_name = &#039;AMERIKA&#039;::bpchar)\n                                       -&amp;gt;  Hash Join\n                                             Hash Voorwaarde: (supplier.s_nationkey = nation.n_nationkey)\n                                             -&amp;gt;  Seq Scan op supplier\n                                             -&amp;gt;  Hash\n                                                   -&amp;gt;  Seq Scan op nation\n                                 -&amp;gt;  Index Scan using idx_partsupp_suppkey op partsupp\n                                       Index Voorwaarde: (ps_suppkey = supplier.s_suppkey)\n               SubPlan 1\n                 -&amp;gt;  Aggregate\n                       -&amp;gt;  Geneste Lus\n                             Join Filter: (nation_1.n_regionkey = region_1.r_regionkey)\n                             -&amp;gt;  Seq Scan op region region_1\n                                   Filter: (r_name = &#039;AMERIKA&#039;::bpchar)\n                             -&amp;gt;  Geneste Lus\n                                   -&amp;gt;  Geneste Lus\n                                         -&amp;gt;  Index Scan using idx_partsupp_partkey op partsupp partsupp_1\n                                               Index Voorwaarde: (part.p_partkey = ps_partkey)\n                                         -&amp;gt;  Index Scan using supplier_pkey op supplier supplier_1\n                                               Index Voorwaarde: (s_suppkey = partsupp_1.ps_suppkey)\n                                   -&amp;gt;  Index Scan using nation_pkey op nation nation_1\n                                         Index Voorwaarde: (n_nationkey = supplier_1.s_nationkey)<\/code><\/pre>\n<p><\/p>\n<p>De node &#171;Merge Join&#187; bevindt zich boven de &#171;Gather Merge&#187;. Daarom gebruikt de samensmelting geen parallelle verwerking. Maar de node &#171;Parallel Index Scan&#187; helpt nog steeds met het segment. <code>part_pkey<\/code>.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-po-sekciyam\">Sectie-gebaseerd samenvoegen<\/h3>\n<p><\/p>\n<p>In PostgreSQL 11 <noindex><a rel=\"nofollow\" href=\"http:\/\/ashutoshpg.blogspot.com\/2017\/12\/partition-wise-joins-divide-and-conquer.html\">sectie-gebaseerd samenvoegen<\/a><\/noindex> staat standaard uit: het heeft een zeer kostbare planning. Tabellen met vergelijkbare secties kunnen sectie voor sectie worden samengevoegd. Op deze manier zal Postgres kleinere hash-tabellen gebruiken. Elke sectie-samenvoeging kan parallel zijn.<\/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                    QUERY PLAN\n---------------------------------------------------\n Append\n   -&gt;  Hash Join\n         Hash Cond: (t2.b = t1.a)\n         -&gt;  Seq Scan on prt2_p1 t2\n               Filter: ((b &gt;= 0) AND (b &lt;= 10000))\n         -&gt;  Hash\n               -&gt;  Seq Scan on prt1_p1 t1\n                     Filter: (b = 0)\n   -&gt;  Hash Join\n         Hash Cond: (t2_1.b = t1_1.a)\n         -&gt;  Seq Scan on prt2_p2 t2_1\n               Filter: ((b &gt;= 0) AND (b &lt;= 10000))\n         -&gt;  Hash\n               -&gt;  Seq Scan on prt1_p2 t1_1\n                     Filter: (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                        QUERY PLAN\n-----------------------------------------------------------\n Gather\n   Workers Planned: 4\n   -&gt;  Parallel Append\n         -&gt;  Parallel Hash Join\n               Hash Cond: (t2_1.b = t1_1.a)\n               -&gt;  Parallel Seq Scan on prt2_p2 t2_1\n                     Filter: ((b &gt;= 0) AND (b &lt;= 10000))\n               -&gt;  Parallel Hash\n                     -&gt;  Parallel Seq Scan on prt1_p2 t1_1\n                           Filter: (b = 0)\n         -&gt;  Parallel Hash Join\n               Hash Cond: (t2.b = t1.a)\n               -&gt;  Parallel Seq Scan on prt2_p1 t2\n                     Filter: ((b &gt;= 0) AND (b &lt;= 10000))\n               -&gt;  Parallel Hash\n                     -&gt;  Parallel Seq Scan on prt1_p1 t1\n                           Filter: (b = 0)<\/code><\/pre>\n<p><\/p>\n<p>Belangrijk is dat sectie-gebaseerd samenvoegen alleen parallel kan zijn als deze secties groot genoeg zijn.<\/p>\n<p><\/p>\n<h3 id=\"parallelnoe-dopolnenie--parallel-append\">Parallel toevoegen - 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> kan worden gebruikt in plaats van verschillende blokken in verschillende werkprocessen. Dit gebeurt meestal bij UNION ALL queries. Het nadeel is minder parallelisme, omdat elk werkproces slechts 1 query verwerkt.<\/p>\n<p><\/p>\n<p>Hier zijn 2 werkprocessen gestart, hoewel er 4 zijn ingeschakeld.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">tpch=# uitleg (kosten uit) select sum(l_quantity) as sum_qty from lineitem where l_shipdate &lt;= date &#039;1998-12-01&#039; - interval &#039;105&#039; dag 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; dag;\n                                           QUERY PLAN\n------------------------------------------------------------------------------------------------\n Verzamel\n   Geplande Werknemers: 2\n   -&gt;  Parallel Voeg samen\n         -&gt;  Aggregate\n               -&gt;  Seq Scan op lineitem\n                     Filter: (l_shipdate &lt;= &#039;2000-08-18 00:00:00&#039;::timestamp zonder tijdzone)\n         -&gt;  Aggregate\n               -&gt;  Seq Scan op lineitem lineitem_1\n                     Filter: (l_shipdate &lt;= &#039;1998-08-18 00:00:00&#039;::timestamp zonder tijdzone)<\/code><\/pre>\n<p><\/p>\n<h3 id=\"samye-vazhnye-peremennye\">De belangrijkste variabelen<\/h3>\n<p><\/p>\n<ul>\n<li>WORK_MEM beperkt de hoeveelheid geheugen voor elk proces, niet alleen voor aanvragen: work_mem <em> processen <\/em> verbindingen = veel geheugen.<\/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 hoeveel werkprocessen het programma zal gebruiken voor parallelle verwerking vanuit het 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 past het totale aantal werkprocessen aan op het aantal CPU-kernen op de 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 hetzelfde, maar voor parallelle werkprocessen.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"itogi\">Conclusies<\/h3>\n<p><\/p>\n<p>Vanaf versie 9.6 kan parallelle verwerking de prestaties van complexe aanvragen, die veel rijen of indexen doorzoeken, aanzienlijk verbeteren. In PostgreSQL 10 is parallelle verwerking standaard ingeschakeld. Vergeet niet het uit te schakelen op servers met een hoge OLTP-werklast. Sequenti\u00eble scans of indexscans verbruiken veel middelen. Als je geen rapport over de volledige dataset uitvoert, kunnen aanvragen effici\u00ebnter worden gemaakt door simpelweg de ontbrekende indexen toe te voegen of het juiste partitioneren te gebruiken.<\/p>\n<p><\/p>\n<h3 id=\"ssylki\">Links<\/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\">Parallelisme in PostgreSQL 11<\/a><\/noindex><\/li>\n<\/ul>\n<p>Bron: <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\/nl\/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=\"nl_NL\" \/>\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\/nl\/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\udd47Parallelle aanvragen in PostgreSQL | ProHoster","description":"Modern CPU's hebben veel kernen.","canonical_url":"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"nl_NL","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\/nl\/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\/nl\/wp-json\/wp\/v2\/posts\/30900","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/comments?post=30900"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts\/30900\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media\/22879"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media?parent=30900"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/categories?post=30900"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/tags?post=30900"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}