{"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\/da\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","title":{"rendered":"Parallelle foresp\u00f8rgsler i PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Parallelle foresp\u00f8rgsler i PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/04\/bbb4b4d3f8714bbdb9b26ada2f2253b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nModerne CPU'er har mange kerner. I \u00e5revis har applikationer sendt foresp\u00f8rgsler til databaser parallelt. Hvis det er en rapporteringsforesp\u00f8rgsel til mange r\u00e6kker i en tabel, udf\u00f8res den hurtigere, n\u00e5r flere CPU'er bruges, og i PostgreSQL er dette muligt fra version 9.6.<\/p>\n<p><\/p>\n<p>Det tog tre \u00e5r at implementere funktionen til parallelle foresp\u00f8rgsler - koden m\u00e5tte skrives om p\u00e5 forskellige trin af foresp\u00f8rgslerne. I PostgreSQL 9.6 blev infrastrukturen til l\u00f8bende forbedringer af koden introduceret. I de efterf\u00f8lgende versioner udf\u00f8res andre typer foresp\u00f8rgsler ogs\u00e5 parallelt.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3 id=\"ogranicheniya\">Begr\u00e6nsninger<\/h3>\n<p><\/p>\n<ul>\n<li>Aktiver ikke parallelt udf\u00f8relse, hvis alle kerner allerede er optaget, ellers vil andre foresp\u00f8rgsler langsomme.<\/li>\n<li>Det vigtigste er, at parallel behandling med h\u00f8je WORK_MEM-v\u00e6rdier bruger meget hukommelse - hver hash-forbindelse eller sortering optager hukommelse svarende til work_mem.<\/li>\n<li>OLTP-foresp\u00f8rgsler med lav forsinkelse kan ikke accelereres ved parallel udf\u00f8relse. Og hvis foresp\u00f8rgslen returnerer \u00e9n r\u00e6kke, vil parallel behandling kun s\u00e6nke den.<\/li>\n<li>Udviklere elsker at bruge TPC-H benchmark. M\u00e5ske har du lignende foresp\u00f8rgsler til ideel parallel udf\u00f8relse.<\/li>\n<li>Kun SELECT-foresp\u00f8rgsler uden pr\u00e6dikatl\u00e5sning udf\u00f8res parallelt.<\/li>\n<li>Nogle gange er korrekt indeksering bedre end sekventiel scanning af tabellen i parallelt mode.<\/li>\n<li>Pause af foresp\u00f8rgsler og mark\u00f8rer underst\u00f8ttes ikke.<\/li>\n<li>Vinduet og aggregatfunktioner til ordnede s\u00e6t er ikke parallelle.<\/li>\n<li>Du f\u00e5r ikke noget ud af input-output arbejdsbelastning.<\/li>\n<li>Der findes ingen parallelle sorteringsalgoritmer. Men foresp\u00f8rgsler med sorteringer kan udf\u00f8res parallelt i nogle aspekter.<\/li>\n<li>Erstat CTE (WITH \u2026) med en indlejret SELECT for at inkludere parallel behandling.<\/li>\n<li>Indpakninger af tredjepartsdata underst\u00f8tter endnu ikke parallel behandling (men kunne g\u00f8re det!)<\/li>\n<li>FULL OUTER JOIN underst\u00f8ttes ikke.<\/li>\n<li>max_rows deaktiverer parallel behandling.<\/li>\n<li>Hvis der i foresp\u00f8rgslen er en funktion, der ikke er markeret som PARALLEL SAFE, vil den v\u00e6re en-tr\u00e5det.<\/li>\n<li>Transaktionsisoleringsniveauet SERIALIZABLE deaktiverer parallel behandling.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"testovaya-sreda\">Testmilj\u00f8<\/h3>\n<p><\/p>\n<p>Udviklerne af PostgreSQL pr\u00f8vede at reducere responstiden for foresp\u00f8rgsler i TPC-H benchmark. Download benchmarken og <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">tilpas den til PostgreSQL<\/a><\/noindex>. Dette er en uofficiel brug af TPC-H benchmark - ikke til sammenligning af databaser eller hardware.<\/p>\n<p><\/p>\n<ol>\n<li>Download TPC-H_Tools_v2.17.3.zip (or a newer version) <noindex><a rel=\"nofollow\" href=\"http:\/\/www.tpc.org\/tpc_documents_current_versions\/current_specifications.asp\">from the TPC website<\/a><\/noindex>.<\/li>\n<li>Rename makefile.suite to Makefile and modify it as described here: <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">https:\/\/github.com\/tvondra\/pg_tpch <\/a><\/noindex>. Compile the code with the command make.<\/li>\n<li>Generate data: <code>.\/dbgen -s 10<\/code> creates a database of 23 GB. This is enough to see the performance difference between parallel and non-parallel queries.<\/li>\n<li>Convert files <code>tbl<\/code> i <code>csv with for<\/code> og <code>sed<\/code>.<\/li>\n<li>Clone the repository <code>pg_tpch<\/code> and copy the files <code>csv<\/code> i <code>pg_tpch\/dss\/data<\/code>.<\/li>\n<li>Create queries with the command <code>qgen<\/code>.<\/li>\n<li>Load data into the database with the command <code>.\/tpch.sh<\/code>.<\/li>\n<\/ol>\n<p><\/p>\n<h3 id=\"parallelnoe-posledovatelnoe-skanirovanie\">Parallel sequential scan<\/h3>\n<p><\/p>\n<p>It may be faster not due to parallel reading but because data is spread across many CPU cores. In modern OS, PostgreSQL data files are well cached. With prefetching, a block larger than requested by the PG daemon can be read from storage. Therefore, the performance of the query is not limited by disk I\/O. It consumes CPU cycles to:<\/p>\n<p><\/p>\n<ul>\n<li>read rows one by one from table pages;<\/li>\n<li>compare row values and conditions <code>HVOR<\/code>.<\/li>\n<\/ul>\n<p><\/p>\n<p>Let's execute a simple query <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>A sequential scan gives too many rows without aggregation, so the query is executed by a single CPU core.<\/p>\n<p><\/p>\n<p>If you add <code>SUM()<\/code>, it shows that two worker processes will help speed up the query:<\/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\">Parallel aggregation<\/h3>\n<p><\/p>\n<p>Noden &#171;Parallel Seq Scan&#187; producerer r\u00e6kker til delvis aggregering. Noden &#171;Partial Aggregate&#187; sk\u00e6rer disse r\u00e6kker med hj\u00e6lp af <code>SUM()<\/code>. I slutningen samles SUM t\u00e6lleren fra hver arbejdsproces af noden &#171;Gather&#187;.<\/p>\n<p><\/p>\n<p>Det endelige resultat beregnes af noden &#171;Finalize Aggregate&#187;. Hvis du har dine egne aggregeringsfunktioner, skal du ikke glemme at markere dem som &#171;parallel safe&#187;.<\/p>\n<p><\/p>\n<h3 id=\"kolichestvo-rabochih-processov\">Antal arbejdsprocesser<\/h3>\n<p><\/p>\n<p>Antallet af arbejdsprocesser kan \u00f8ges uden genstart af serveren:<\/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>Hvad sker der her? Antallet af arbejdsprocesser er blevet fordoblet, og foresp\u00f8rgslen blev kun 1,6599 gange hurtigere. Beregningerne er interessante. Vi havde 2 arbejdsprocesser og 1 leder. Efter \u00e6ndringen blev det 4+1.<\/p>\n<p><\/p>\n<p>Vores maksimale acceleration fra parallelbehandling: 5\/3 = 1,66(6) gange.<\/p>\n<p><\/p>\n<h2 id=\"kak-eto-rabotaet\">Hvordan fungerer det?<\/h2>\n<p><\/p>\n<h3 id=\"processy\">Processer<\/h3>\n<p><\/p>\n<p>Udf\u00f8relsen af foresp\u00f8rgslen begynder altid med den ledende proces. Lederen udf\u00f8rer alt, der ikke er parallelt, og en del af den parallelle behandling. Andre processer, der udf\u00f8rer de samme foresp\u00f8rgsler, kaldes arbejdsprocesser. Parallelbehandling bruger infrastrukturen <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/bgworker.html\">af dynamiske baggrundsarbejdsprocesser<\/a><\/noindex> (siden version 9.4). Da andre dele af PostgreSQL bruger processer, og ikke tr\u00e5de, kunne en foresp\u00f8rgsel med 3 arbejdsprocesser v\u00e6re 4 gange hurtigere end traditionel behandling.<\/p>\n<p><\/p>\n<h3 id=\"vzaimodeystvie\">Interaktion<\/h3>\n<p><\/p>\n<p>Arbejdsprocesserne kommunikerer med lederen via en meddelelsesk\u00f8 (baseret p\u00e5 delt hukommelse). Hver proces har 2 k\u00f8er: til fejl og til tuples.<\/p>\n<p><\/p>\n<h3 id=\"skolko-nuzhno-rabochih-processov\">Hvor mange arbejdsprocesser er n\u00f8dvendige?<\/h3>\n<p><\/p>\n<p>Det minimale loft gives af parameteren <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>. Derefter tager foresp\u00f8rgselsudf\u00f8reren arbejdsprocesser fra puljen, som er begr\u00e6nset af parameteren <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>. Den sidste begr\u00e6nsning er <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>, hvilket er det samlede antal baggrundsprocesser.<\/p>\n<p><\/p>\n<p>Hvis det ikke er muligt at allokere en arbejdsproces, vil behandlingen v\u00e6re en-proces.<\/p>\n<p><\/p>\n<p>Foresp\u00f8rgselsplanl\u00e6ggeren kan reducere arbejdsprocesserne afh\u00e6ngigt af st\u00f8rrelsen p\u00e5 tabellen eller indekset. Der er parametre til dette <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> og <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 arbejder\n24MB tabel =&gt; 2 arbejdere\n72MB tabel =&gt; 3 arbejdere\nx =&gt; log(x \/ min_parallel_table_scan_size) \/ log(3) + 1 arbejder<\/code><\/pre>\n<p><\/p>\n<p>Hver gang tabellen er 3 gange st\u00f8rre end <code>min_parallel_(index|table)_scan_size<\/code>, tilf\u00f8jer Postgres en arbejdsproces. Antallet af arbejdsprocesser er ikke baseret p\u00e5 omkostninger. Cirkul\u00e6r afh\u00e6ngighed komplicerer komplekse implementeringer. I stedet bruger planl\u00e6ggeren enkle regler.<\/p>\n<p><\/p>\n<p>I praksis er disse regler ikke altid passende til produktionen, s\u00e5 man kan \u00e6ndre antallet af arbejdsprocesser for en bestemt tabel: ALTER TABLE \u2026 SET (<code>parallel_workers = N<\/code>).<\/p>\n<p><\/p>\n<h3 id=\"pochemu-parallelnaya-obrabotka-ne-ispolzuetsya\">Hvorfor bruges parallelbehandling ikke?<\/h3>\n<p><\/p>\n<p>Udover den lange liste af begr\u00e6nsninger er der ogs\u00e5 omkostningskontroller:<\/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 for at undg\u00e5 parallel behandling af korte foresp\u00f8rgsler. Denne parameter estimerer tiden til at forberede hukommelsen, starte processen og den indledende dataudveksling.<\/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>: kommunikationen mellem lederen og arbejdstagerne kan tr\u00e6kke ud i forhold til antallet af tuples fra arbejdsprocesserne. Denne parameter beregner omkostningerne ved dataudveksling.<\/p>\n<p><\/p>\n<h3 id=\"soedineniya-vlozhennyh-ciklov--nested-loop-join\">Nedlagte loop-sammenf\u00f8jning \u2014 Nested Loop Join<\/h3>\n<p><\/p>\n<pre><code class=\"plaintext\">PostgreSQL 9.6+ kan udf\u00f8re indlejrede l\u00f8kker parallelt \u2014 det er en simpel operation.\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>Indsamlingen sker i det sidste trin, s\u00e5 Nested Loop Left Join er en parallel operation. Parallel Index Only Scan kom f\u00f8rst med version 10. Den fungerer p\u00e5 samme m\u00e5de som parallel sekventiel scanning. Betingelsen <code>c_custkey = o_custkey<\/code> l\u00e6sser \u00e9n ordre for hver kundelinje. S\u00e5 det er ikke parallelt.<\/p>\n<p><\/p>\n<h3 id=\"hesh-soedinenie--hash-join\">Hash-sammenf\u00f8jning \u2014 Hash Join<\/h3>\n<p><\/p>\n<p>Hver arbejdsproces opretter sin egen hash-tabel indtil PostgreSQL 11. Og hvis der er mere end fire processer, vil ydeevnen ikke stige. I den nye version er hash-tabellen f\u00e6lles. Hver arbejdsproces kan bruge WORK_MEM til at oprette en hash-tabel.<\/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>Foresp\u00f8rgsel 12 fra TPC-H viser tydeligt parallel hash join. Hver arbejdsgang deltager i oprettelsen af en f\u00e6lles hash-tabel.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-sliyaniem--merge-join\">Sammenf\u00f8jning - Merge Join<\/h3>\n<p><\/p>\n<p>Sammenf\u00f8jning er i sin natur ikke parallel. Bekymr dig ikke, hvis dette er det sidste trin i foresp\u00f8rgslen - det kan stadig udf\u00f8res parallelt.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">-- Query 2 fra TPC-H\nforklar (omkostninger fra) v&aelig;lg s_acctbal, s_name, n_name, p_partkey, p_mfgr, s_address, s_phone, s_comment\nfra    part, leverand&oslash;r, partsupp, nation, region\nhvor\n        p_partkey = ps_partkey\n        og s_suppkey = ps_suppkey\n        og p_size = 36\n        og p_type som &#039;%BRASS&#039;\n        og s_nationkey = n_nationkey\n        og n_regionkey = r_regionkey\n        og r_name = &#039;AMERIKA&#039;\n        og ps_supplycost = (\n                v&aelig;lg\n                        min(ps_supplycost)\n                fra    partsupp, leverand&oslash;r, nation, region\n                hvor\n                        p_partkey = ps_partkey\n                        og s_suppkey = ps_suppkey\n                        og s_nationkey = n_nationkey\n                        og n_regionkey = r_regionkey\n                        og r_name = &#039;AMERIKA&#039;\n        )\nbestil efter s_acctbal desc, n_name, s_name, p_partkey\nBEGR&AElig;NS 100;\n                                                QUERY PLAN\n----------------------------------------------------------------------------------------------------------\n Begr&aelig;nsning\n   -&amp;gt;  Sorter\n         Sort&eacute;r n&oslash;gle: supplier.s_acctbal DESC, nation.n_name, supplier.s_name, part.p_partkey\n         -&amp;gt;  Merge Join\n               Merge betingelse: (part.p_partkey = partsupp.ps_partkey)\n               Join filter: (partsupp.ps_supplycost = (SubPlan 1))\n               -&amp;gt;  Saml Merge\n                     Arbejdere planlagt: 4\n                     -&amp;gt;  Parallel indeks scanning ved brug af &lt;strong&gt;part_pkey&lt;\/strong&gt; p&aring; part\n                           Filter: (((p_type)::text ~~ &#039;%BRASS&#039;::text) OG (p_size = 36))\n               -&amp;gt;  Materialiser\n                     -&amp;gt;  Sorter\n                           Sort&eacute;r n&oslash;gle: partsupp.ps_partkey\n                           -&amp;gt;  Indlejret l&oslash;kke\n                                 -&amp;gt;  Indlejret l&oslash;kke\n                                       Join filter: (nation.n_regionkey = region.r_regionkey)\n                                       -&amp;gt;  Sekventiel scanning p&aring; region\n                                             Filter: (r_name = &#039;AMERIKA&#039;::bpchar)\n                                       -&amp;gt;  Hash Join\n                                             Hash betingelse: (supplier.s_nationkey = nation.n_nationkey)\n                                             -&amp;gt;  Sekventiel scanning p&aring; leverand&oslash;r\n                                             -&amp;gt;  Hash\n                                                   -&amp;gt;  Sekventiel scanning p&aring; nation\n                                 -&amp;gt;  Indeks scanning ved brug af idx_partsupp_suppkey p&aring; partsupp\n                                       Indeks betingelse: (ps_suppkey = supplier.s_suppkey)\n               SubPlan 1\n                 -&amp;gt;  Aggregat\n                       -&amp;gt;  Indlejret l&oslash;kke\n                             Join filter: (nation_1.n_regionkey = region_1.r_regionkey)\n                             -&amp;gt;  Sekventiel scanning p&aring; region region_1\n                                   Filter: (r_name = &#039;AMERIKA&#039;::bpchar)\n                             -&amp;gt;  Indlejret l&oslash;kke\n                                   -&amp;gt;  Indlejret l&oslash;kke\n                                         -&amp;gt;  Indeks scanning ved brug af idx_partsupp_partkey p&aring; partsupp partsupp_1\n                                               Indeks betingelse: (part.p_partkey = ps_partkey)\n                                         -&amp;gt;  Indeks scanning ved brug af supplier_pkey p&aring; leverand&oslash;r supplier_1\n                                               Indeks betingelse: (s_suppkey = partsupp_1.ps_suppkey)\n                                   -&amp;gt;  Indeks scanning ved brug af nation_pkey p&aring; nation nation_1\n                                         Indeks betingelse: (n_nationkey = supplier_1.s_nationkey)<\/code><\/pre>\n<p><\/p>\n<p>Noden &#171;Merge Join&#187; ligger ovenfor &#171;Gather Merge&#187;. S\u00e5 fusionen bruger ikke parallel behandling. Men noden &#171;Parallel Index Scan&#187; hj\u00e6lper stadig med segmentet. <code>part_pkey<\/code>.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-po-sekciyam\">Sammenf\u00f8jning efter sektioner<\/h3>\n<p><\/p>\n<p>I PostgreSQL 11 <noindex><a rel=\"nofollow\" href=\"http:\/\/ashutoshpg.blogspot.com\/2017\/12\/partition-wise-joins-divide-and-conquer.html\">sammenf\u00f8jning efter sektioner<\/a><\/noindex> er som standard deaktiveret: den har meget omkostningsfuld planl\u00e6gning. Tabeller med lignende sektionering kan sammensl\u00e5s sektion for sektion. S\u00e5 Postgres vil bruge mindre hash-tabeller. Hver sektion sammenf\u00f8jning kan v\u00e6re parallel.<\/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>Det vigtigste er, at sammenf\u00f8jning efter sektioner kun kan v\u00e6re parallel, hvis disse sektioner er store nok.<\/p>\n<p><\/p>\n<h3 id=\"parallelnoe-dopolnenie--parallel-append\">Parallel tilf\u00f8jelse - 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 bruges i stedet for forskellige blokke i forskellige arbejdsgange. Dette ses ofte med UNION ALL foresp\u00f8rgsler. Ulempen er mindre parallelisme, da hver arbejdsgang kun behandler 1 foresp\u00f8rgsel.<\/p>\n<p><\/p>\n<p>Her k\u00f8rer 2 arbejdsgange, selvom 4 er inkluderet.<\/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\">De vigtigste variable<\/h3>\n<p><\/p>\n<ul>\n<li>WORK_MEM begr\u00e6nser den m\u00e6ngde hukommelse, der er til r\u00e5dighed for hver proces, ikke kun for foresp\u00f8rgsler: work_mem <em> processer <\/em> forbindelser = meget hukommelse.<\/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 hvor mange arbejdsprocesser programmet vil bruge til paralleldbehandling af planen.<\/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 tilpasser det samlede antal arbejdsprocesser efter antallet af CPU-kerner p\u00e5 serveren.<\/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 det samme, men for parallele arbejdsprocesser.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"itogi\">Resum\u00e9<\/h3>\n<p><\/p>\n<p>Fra version 9.6 kan paralleldbehandling v\u00e6sentligt forbedre ydeevnen af komplekse foresp\u00f8rgsler, der scanner mange r\u00e6kker eller indekser. I PostgreSQL 10 er paralleldbehandling sl\u00e5et til som standard. Husk at deaktivere det p\u00e5 servere med h\u00f8j OLTP-belastning. Sekventielle scanninger eller indeksscanninger bruger meget ressourcer. Hvis du ikke udf\u00f8rer rapporten p\u00e5 hele datas\u00e6ttet, kan foresp\u00f8rgsler g\u00f8res mere effektive ved blot at tilf\u00f8je manglende indekser eller bruge korrekt partitionering.<\/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\">Parallellisme i PostgreSQL 11<\/a><\/noindex><\/li>\n<\/ul>\n<p>Kilde: <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\/da\/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=\"da_DK\" \/>\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\/da\/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\udd47Parallele foresp\u00f8rgsler i PostgreSQL | ProHoster","description":"Moderne CPU'er har mange kernen.","canonical_url":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"da_DK","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\/da\/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\/da\/wp-json\/wp\/v2\/posts\/30900","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/comments?post=30900"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts\/30900\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/media\/22879"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/media?parent=30900"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/categories?post=30900"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/tags?post=30900"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}