{"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\/it\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","title":{"rendered":"Richieste parallele in PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Richieste parallele in PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/04\/bbb4b4d3f8714bbdb9b26ada2f2253b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nNei moderni CP ci sono moltissimi core. Per anni, le applicazioni hanno inviato richieste ai database in parallelo. Se si tratta di una richiesta di report su molte righe nella tabella, viene eseguita pi\u00f9 rapidamente quando utilizza pi\u00f9 CP, e in PostgreSQL ci\u00f2 \u00e8 possibile a partire dalla versione 9.6.<\/p>\n<p><\/p>\n<p>Ci sono voluti 3 anni per implementare la funzione delle richieste parallele \u2014 \u00e8 stato necessario riscrivere il codice in diverse fasi dell'esecuzione delle richieste. In PostgreSQL 9.6 \u00e8 stata introdotta un'infrastruttura per un ulteriore miglioramento del codice. Nelle versioni successive, anche altri tipi di richieste vengono eseguiti in parallelo.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3 id=\"ogranicheniya\">Limitazioni<\/h3>\n<p><\/p>\n<ul>\n<li>Non attivare l'esecuzione parallela se tutti i core sono gi\u00e0 occupati, altrimenti altre richieste saranno rallentate.<\/li>\n<li>La cosa pi\u00f9 importante \u00e8 che l'elaborazione parallela con valori elevati di WORK_MEM utilizza molta memoria: ogni connessione hash o ordinamento occupa memoria per un ammontare di work_mem.<\/li>\n<li>Le richieste OLTP con bassa latenza non possono essere accelerate mediante l'esecuzione parallela. Se una richiesta restituisce una sola riga, l'elaborazione parallela non far\u00e0 altro che rallentarla.<\/li>\n<li>Gli sviluppatori amano utilizzare il benchmark TPC-H. Forse hai richieste simili per un'esecuzione parallela ottimale.<\/li>\n<li>Solo le richieste SELECT senza blocchi predicati vengono eseguite in parallelo.<\/li>\n<li>A volte una corretta indicizzazione \u00e8 migliore della scansione sequenziale della tabella in modalit\u00e0 parallela.<\/li>\n<li>La sospensione delle richieste e i cursori non sono supportati.<\/li>\n<li>Le funzioni finestra e le funzioni aggregate dei set ordinati non sono parallele.<\/li>\n<li>Non guadagnate nulla in carico di I\/O.<\/li>\n<li>Non esistono algoritmi di ordinamento paralleli. Tuttavia, le richieste con ordinamenti possono essere eseguite in parallelo in alcuni aspetti.<\/li>\n<li>Sostituisci CTE (WITH \u2026) con un SELECT annidato per includere l'elaborazione parallela.<\/li>\n<li>I wrapper di dati di terze parti non supportano ancora l'elaborazione parallela (anche se potrebbero!).<\/li>\n<li>FULL OUTER JOIN non \u00e8 supportato.<\/li>\n<li>max_rows disabilita l'elaborazione parallela.<\/li>\n<li>Se nella richiesta \u00e8 presente una funzione non contrassegnata come PARALLEL SAFE, essa sar\u00e0 monothread.<\/li>\n<li>Il livello di isolamento della transazione SERIALIZABLE disabilita l'elaborazione parallela.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"testovaya-sreda\">Ambiente di test<\/h3>\n<p><\/p>\n<p>Gli sviluppatori di PostgreSQL hanno cercato di ridurre i tempi di risposta delle richieste del benchmark TPC-H. Scarica il benchmark e <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">adattalo a PostgreSQL<\/a><\/noindex>. Questo utilizzo non ufficiale del benchmark TPC-H non \u00e8 per il confronto di database o hardware.<\/p>\n<p><\/p>\n<ol>\n<li>Carica TPC-H_Tools_v2.17.3.zip (o una versione pi\u00f9 recente) <noindex><a rel=\"nofollow\" href=\"http:\/\/www.tpc.org\/tpc_documents_current_versions\/current_specifications.asp\">dal sito ufficiale TPC<\/a><\/noindex>.<\/li>\n<li>Rinomina makefile.suite in Makefile e modifica come descritto qui: <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">https:\/\/github.com\/tvondra\/pg_tpch <\/a><\/noindex>. Compila il codice con il comando make.<\/li>\n<li>Genera i dati: <code>.\\\/dbgen -s 10<\/code> crea un database di 23 GB. Questo \u00e8 sufficiente per vedere la differenza nelle prestazioni delle query parallele e non parallele.<\/li>\n<li>Converti i file <code>tbl<\/code> in <code>csv con for<\/code> e <code>sed<\/code>.<\/li>\n<li>Clona il repository <code>pg_tpch<\/code> e copia i file <code>csv<\/code> in <code>pg_tpch\\\/dss\\\/data<\/code>.<\/li>\n<li>Crea le query con il comando <code>qgen<\/code>.<\/li>\n<li>Carica i dati nel database con il comando <code>.\\\/tpch.sh<\/code>.<\/li>\n<\/ol>\n<p><\/p>\n<h3 id=\"parallelnoe-posledovatelnoe-skanirovanie\">Scansione sequenziale parallela<\/h3>\n<p><\/p>\n<p>Pu\u00f2 risultare pi\u00f9 veloce non a causa della lettura parallela, ma perch\u00e9 i dati sono distribuiti su molti core della CPU. Nei sistemi operativi moderni, i file di dati PostgreSQL vengono ben memorizzati nella cache. Con la lettura anticipata \u00e8 possibile ottenere dal magazzino un blocco pi\u00f9 grande rispetto a quello richiesto dal demone PG. Pertanto, le prestazioni della query non sono limitate dall'I\/O del disco. Consuma cicli della CPU per:<\/p>\n<p><\/p>\n<ul>\n<li>leggere le righe una ad una dalle pagine della tabella;<\/li>\n<li>confrontare i valori delle righe e le condizioni <code>DOVE<\/code>.<\/li>\n<\/ul>\n<p><\/p>\n<p>Eseguiamo una semplice 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 senza fuso orario)\nRighe rimosse dal filtro: 1146337\nTempo di pianificazione: 0.203 ms\nTempo di esecuzione: 19035.100 ms<\/code><\/pre>\n<p><\/p>\n<p>La scansione sequenziale restituisce troppe righe senza aggregazione, quindi la query viene eseguita da un solo core della CPU.<\/p>\n<p><\/p>\n<p>Se aggiungiamo <code>SUM()<\/code>, si nota che due processi di lavoro aiutano ad accelerare la query:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">explain analyze select sum(l_quantity) as sum_qty from lineitem where l_shipdate &lt;= date &#039;1998-12-01&#039; - interval &#039;105&#039; day;\nQUERY PLAN\n----------------------------------------------------------------------------------------------------------------------------------------------------\nFinalize Aggregate (cost=1589702.14..1589702.15 rows=1 width=32) (actual time=8553.365..8553.365 rows=1 loops=1)\n-&gt; Gather (cost=1589701.91..1589702.12 rows=2 width=32) (actual time=8553.241..8555.067 rows=3 loops=1)\nWorkers pianificati: 2\nWorkers lanciati: 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 senza fuso orario)\nRighe rimosse dal filtro: 382112\nTempo di pianificazione: 0.241 ms\nTempo di esecuzione: 8555.131 ms<\/code><\/pre>\n<p><\/p>\n<h3 id=\"parallelnaya-agregaciya\">Aggregazione parallela<\/h3>\n<p><\/p>\n<p>Il nodo &#171;Parallel Seq Scan&#187; produce righe per l'aggregazione parziale. Il nodo &#171;Partial Aggregate&#187; riduce queste righe tramite <code>SUM()<\/code>. Alla fine, il contatore SUM di ogni processo operativo viene raccolto dal nodo &#171;Gather&#187;.<\/p>\n<p><\/p>\n<p>Il risultato finale \u00e8 calcolato dal nodo &#171;Finalize Aggregate&#187;. Se hai funzioni di aggregazione personalizzate, non dimenticare di contrassegnarle come &#171;parallel safe&#187;.<\/p>\n<p><\/p>\n<h3 id=\"kolichestvo-rabochih-processov\">Numero di processi di lavoro<\/h3>\n<p><\/p>\n<p>Il numero di processi di lavoro pu\u00f2 essere aumentato senza riavviare il server:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">explain analyze select sum(l_quantity) as sum_qty from lineitem where l_shipdate &lt;= date &#039;1998-12-01&#039; - interval &#039;105&#039; day;\nQUERY PLAN\n----------------------------------------------------------------------------------------------------------------------------------------------------\nFinalize Aggregate (cost=1589702.14..1589702.15 rows=1 width=32) (actual time=8553.365..8553.365 rows=1 loops=1)\n-&gt; Gather (cost=1589701.91..1589702.12 rows=2 width=32) (actual time=8553.241..8555.067 rows=3 loops=1)\nWorkers pianificati: 2\nWorkers lanciati: 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 senza fuso orario)\nRighe rimosse dal filtro: 382112\nTempo di pianificazione: 0.241 ms\nTempo di esecuzione: 8555.131 ms<\/code><\/pre>\n<p><\/p>\n<p>Cosa sta succedendo qui? I processi di lavoro sono raddoppiati, mentre la richiesta \u00e8 diventata solo 1,6599 volte pi\u00f9 veloce. I calcoli sono interessanti. Avevamo 2 processi di lavoro e 1 leader. Dopo la modifica, sono diventati 4+1.<\/p>\n<p><\/p>\n<p>La nostra massima accelerazione dalla lavorazione parallela: 5\/3 = 1,66(6) volte.<\/p>\n<p><\/p>\n<h2 id=\"kak-eto-rabotaet\">Come funziona?<\/h2>\n<p><\/p>\n<h3 id=\"processy\">Processi<\/h3>\n<p><\/p>\n<p>L'esecuzione della richiesta inizia sempre con il processo guida. Il leader gestisce tutto ci\u00f2 che non \u00e8 paralellizzato e parte del trattamento parallelo. Gli altri processi, che eseguono le stesse richieste, vengono chiamati processi di lavoro. L'elaborazione parallela utilizza l'infrastruttura <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/bgworker.html\">dei processi di lavoro in background dinamici<\/a><\/noindex> (dalla versione 9.4). Poich\u00e9 altre parti di PostgreSQL utilizzano processi e non thread, una richiesta con 3 processi di lavoro potrebbe essere 4 volte pi\u00f9 veloce rispetto all'elaborazione tradizionale.<\/p>\n<p><\/p>\n<h3 id=\"vzaimodeystvie\">Interazione<\/h3>\n<p><\/p>\n<p>I processi di lavoro comunicano con il leader tramite una coda di messaggi (basata su memoria condivisa). Ogni processo ha 2 code: per gli errori e per le tuple.<\/p>\n<p><\/p>\n<h3 id=\"skolko-nuzhno-rabochih-processov\">Quanti processi di lavoro sono necessari?<\/h3>\n<p><\/p>\n<p>Il limite minimo \u00e8 impostato dal parametro <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>. Poi l'esecutore delle query prende i processi di lavoro dal pool, limitato dal parametro <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>. L'ultimo limite \u00e8 dato da <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>, cio\u00e8 il numero totale di processi in background.<\/p>\n<p><\/p>\n<p>Se non \u00e8 stato possibile allocare un processo di lavoro, l'elaborazione sar\u00e0 monoprocessuale.<\/p>\n<p><\/p>\n<p>Il pianificatore delle query pu\u00f2 ridurre i processi di lavoro a seconda delle dimensioni della tabella o dell'indice. Ci sono parametri per questo <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> e <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 tabella =&gt; 1 lavoratore\n24MB tabella =&gt; 2 lavoratori\n72MB tabella =&gt; 3 lavoratori\nx =&gt; log(x \/ min_parallel_table_scan_size) \/ log(3) + 1 lavoratore<\/code><\/pre>\n<p><\/p>\n<p>Ogni volta che la tabella \u00e8 3 volte pi\u00f9 grande di <code>min_parallel_(index|table)_scan_size<\/code>, Postgres aggiunge un processo di lavoro. Il numero di processi di lavoro non si basa sui costi. La dipendenza circolare rende difficili le implementazioni complesse. Invece, il pianificatore utilizza regole semplici.<\/p>\n<p><\/p>\n<p>Nella pratica queste regole non sono sempre adatte per la produzione, quindi \u00e8 possibile modificare il numero di processi di lavoro per una tabella specifica: ALTER TABLE \u2026 SET (<code>parallel_workers = N<\/code>).<\/p>\n<p><\/p>\n<h3 id=\"pochemu-parallelnaya-obrabotka-ne-ispolzuetsya\">Perch\u00e9 non viene utilizzata l'elaborazione parallela?<\/h3>\n<p><\/p>\n<p>Oltre a un lungo elenco di limitazioni, ci sono anche controlli sui costi:<\/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 per evitar di gestire in parallelo richieste brevi. Questo parametro stima il tempo per la preparazione della memoria, l'avvio del processo e lo scambio iniziale di dati.<\/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>: la comunicazione tra il leader e i lavoratori pu\u00f2 allungarsi proporzionalmente al numero di tuple dai processi di lavoro. Questo parametro calcola i costi per lo scambio di dati.<\/p>\n<p><\/p>\n<h3 id=\"soedineniya-vlozhennyh-ciklov--nested-loop-join\">Join a cicli annidati \u2014 Nested Loop Join<\/h3>\n<p><\/p>\n<pre><code class=\"plaintext\">PostgreSQL 9.6+ pu\u00f2 eseguire cicli annidati in parallelo \u2014 \u00e8 un'operazione semplice.\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>Il raccolto avviene nell'ultima fase, quindi il Nested Loop Left Join \u00e8 un'operazione in parallelo. Il Parallel Index Only Scan \u00e8 apparso solo nella versione 10. Funziona in modo analogo alla scansione sequenziale parallela. La condizione <code>c_custkey = o_custkey<\/code> legge un ordine per ciascuna riga del cliente. Quindi non \u00e8 parallela.<\/p>\n<p><\/p>\n<h3 id=\"hesh-soedinenie--hash-join\">Hash Join \u2014 Hash Join<\/h3>\n<p><\/p>\n<p>Ogni processo di lavoro crea la propria tabella hash fino a PostgreSQL 11. E se ci sono pi\u00f9 di quattro di questi processi, le prestazioni non aumenteranno. Nella nuova versione, la tabella hash \u00e8 condivisa. Ogni processo di lavoro pu\u00f2 utilizzare WORK_MEM per creare una tabella hash.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">seleziona\n        l_shipmode,\n        somma(caso\n                quando o_orderpriority = '1-URGENTE'\n                        o o_orderpriority = '2-ALTA'\n                        allora 1\n                altro 0\n        fine) come high_line_count,\n        somma(caso\n                quando o_orderpriority  '1-URGENTE'\n                        e o_orderpriority  '2-ALTA'\n                        allora 1\n                altro 0\n        fine) come low_line_count\nda\n        ordini,\n        lineitem\ndove\n        o_orderkey = l_orderkey\n        e l_shipmode in ('MAIL', 'ARIA')\n        e l_commitdate &lt; l_receiptdate\n        e l_shipdate = data '1996-01-01'\n        e l_receiptdate &lt; data &#039;1996-01-01&#039; + intervallo &#039;1&#039; anno\ngruppo per\n        l_shipmode\nordine per\n        l_shipmode\nLIMIT 1;\n                                                                                                                                    PIANO QUERY\n-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n Limit  (costo=1964755.66..1964961.44 righe=1 larghezza=27) (tempo effettivo=7579.592..7922.997 righe=1 cicli=1)\n   -&gt;  Finalizza GroupAggregate  (costo=1964755.66..1966196.11 righe=7 larghezza=27) (tempo effettivo=7579.590..7579.591 righe=1 cicli=1)\n         Chiave di gruppo: lineitem.l_shipmode\n         -&gt;  Raggruppa Merge  (costo=1964755.66..1966195.83 righe=28 larghezza=27) (tempo effettivo=7559.593..7922.319 righe=6 cicli=1)\n               Lavoratori pianificati: 4\n               Lavoratori lanciati: 4\n               -&gt;  Gruppo Parziale Aggregato  (costo=1963755.61..1965192.44 righe=7 larghezza=27) (tempo effettivo=7548.103..7564.592 righe=2 cicli=5)\n                     Chiave di gruppo: lineitem.l_shipmode\n                     -&gt;  Ordina  (costo=1963755.61..1963935.20 righe=71838 larghezza=27) (tempo effettivo=7530.280..7539.688 righe=62519 cicli=5)\n                           Chiave di ordinamento: lineitem.l_shipmode\n                           Metodo di ordinamento: fusione esterna  Disco: 2304kB\n                           Lavoratore 0:  Metodo di ordinamento: fusione esterna  Disco: 2064kB\n                           Lavoratore 1:  Metodo di ordinamento: fusione esterna  Disco: 2384kB\n                           Lavoratore 2:  Metodo di ordinamento: fusione esterna  Disco: 2264kB\n                           Lavoratore 3:  Metodo di ordinamento: fusione esterna  Disco: 2336kB\n                           -&gt;  Unione Hash parallela  (costo=382571.01..1957960.99 righe=71838 larghezza=27) (tempo effettivo=7036.917..7499.692 righe=62519 cicli=5)\n                                 Condizione Hash: (lineitem.l_orderkey = orders.o_orderkey)\n                                 -&gt;  Scansione Seq parallela su lineitem  (costo=0.00..1552386.40 righe=71838 larghezza=19) (tempo effettivo=0.583..4901.063 righe=62519 cicli=5)\n                                       Filtro: ((l_shipmode = QUALSIASI (&#039;{MAIL,ARIA}&#039;::bpchar[])) E (l_commitdate &lt; l_receiptdate) E (l_shipdate = '1996-01-01'::data) E (l_receiptdate &lt; &#039;1997-01-01 00:00:00&#039;::timestamp senza fuso orario))\n                                       Righe rimosse dal filtro: 11934691\n                                 -&gt;  Hash parallelo  (costo=313722.45..313722.45 righe=3750045 larghezza=20) (tempo effettivo=2011.518..2011.518 righe=3000000 cicli=5)\n                                       Focolari: 65536  Batches: 256  Utilizzo memoria: 3840kB\n                                       -&gt;  Scansione Seq parallela su ordini  (costo=0.00..313722.45 righe=3750045 larghezza=20) (tempo effettivo=0.029..995.948 righe=3000000 cicli=5)\n Tempo di pianificazione: 0.977 ms\n Tempo di esecuzione: 7923.770 ms<\/code><\/pre>\n<p><\/p>\n<p>La Query 12 di TPC-H mostra chiaramente la connessione hash parallela. Ogni processo di lavoro partecipa alla creazione di una tabella hash comune.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-sliyaniem--merge-join\">Unione per fusione \u2014 Merge Join<\/h3>\n<p><\/p>\n<p>L'unione per fusione \u00e8 intrinsecamente non parallela. Non preoccupatevi se questo \u00e8 l'ultimo passaggio della query, pu\u00f2 comunque essere eseguito in parallelo.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">-- Query 2 da TPC-H\nspiega (costi disattivati) seleziona s_acctbal, s_name, n_name, p_partkey, p_mfgr, s_address, s_phone, s_comment\nda    part, supplier, partsupp, nation, region\ndove\n        p_partkey = ps_partkey\n        e s_suppkey = ps_suppkey\n        e p_size = 36\n        e p_type like &#039;%BRASS&#039;\n        e s_nationkey = n_nationkey\n        e n_regionkey = r_regionkey\n        e r_name = &#039;AMERICA&#039;\n        e ps_supplycost = (\n                seleziona\n                        min(ps_supplycost)\n                da    partsupp, supplier, nation, region\n                dove\n                        p_partkey = ps_partkey\n                        e s_suppkey = ps_suppkey\n                        e s_nationkey = n_nationkey\n                        e n_regionkey = r_regionkey\n                        e r_name = &#039;AMERICA&#039;\n        )\nordina per s_acctbal desc, n_name, s_name, p_partkey\nLIMIT 100;\n                                                PIANTA DELLA QUERY\n----------------------------------------------------------------------------------------------------------\n Limit\n   -&amp;gt;  Ordina\n         Chiave di ordinamento: supplier.s_acctbal DESC, nation.n_name, supplier.s_name, part.p_partkey\n         -&amp;gt;  Merge Join\n               Condizione di unione: (part.p_partkey = partsupp.ps_partkey)\n               Filtro di unione: (partsupp.ps_supplycost = (SubPiano 1))\n               -&amp;gt;  Raccogli Merge\n                     Lavoratori pianificati: 4\n                     -&amp;gt;  Scansione Indice Parallela usando &lt;strong&gt;part_pkey&lt;\/strong&gt; su parte\n                           Filtro: (((p_type)::text ~~ &#039;%BRASS&#039;::text) E (p_size = 36))\n               -&amp;gt;  Materializza\n                     -&amp;gt;  Ordina\n                           Chiave di ordinamento: partsupp.ps_partkey\n                           -&amp;gt;  Ciclo annidato\n                                 -&amp;gt;  Ciclo annidato\n                                       Filtro di unione: (nation.n_regionkey = region.r_regionkey)\n                                       -&amp;gt;  Scansione sequenziale su region\n                                             Filtro: (r_name = &#039;AMERICA&#039;::bpchar)\n                                       -&amp;gt;  Hash Join\n                                             Condizione Hash: (supplier.s_nationkey = nation.n_nationkey)\n                                             -&amp;gt;  Scansione sequenziale su supplier\n                                             -&amp;gt;  Hash\n                                                   -&amp;gt;  Scansione sequenziale su nation\n                                 -&amp;gt;  Scansione Indice usando idx_partsupp_suppkey su partsupp\n                                       Condizione indice: (ps_suppkey = supplier.s_suppkey)\n               SubPiano 1\n                 -&amp;gt;  Aggregato\n                       -&amp;gt;  Ciclo annidato\n                             Filtro di unione: (nation_1.n_regionkey = region_1.r_regionkey)\n                             -&amp;gt;  Scansione sequenziale su region region_1\n                                   Filtro: (r_name = &#039;AMERICA&#039;::bpchar)\n                             -&amp;gt;  Ciclo annidato\n                                   -&amp;gt;  Ciclo annidato\n                                         -&amp;gt;  Scansione Indice usando idx_partsupp_partkey su partsupp partsupp_1\n                                               Condizione indice: (part.p_partkey = ps_partkey)\n                                         -&amp;gt;  Scansione Indice usando supplier_pkey su supplier supplier_1\n                                               Condizione indice: (s_suppkey = partsupp_1.ps_suppkey)\n                                   -&amp;gt;  Scansione Indice usando nation_pkey su nation nation_1\n                                         Condizione indice: (n_nationkey = supplier_1.s_nationkey)<\/code><\/pre>\n<p><\/p>\n<p>Il nodo &#171;Merge Join&#187; si trova sopra &#171;Gather Merge&#187;. Quindi la fusione non utilizza l'elaborazione parallela. Ma il nodo &#171;Parallel Index Scan&#187; aiuta comunque con il segmento. <code>part_pkey<\/code>.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-po-sekciyam\">Unione per sezioni<\/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\">unione per sezioni<\/a><\/noindex> \u00e8 disattivata per impostazione predefinita: ha una pianificazione molto costosa. Le tabelle con sezioni simili possono essere unite sezione per sezione. In questo modo Postgres utilizzer\u00e0 tabelle hash pi\u00f9 piccole. Ogni unione di sezioni pu\u00f2 essere parallela.<\/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>Soprattutto, l'unione per sezioni pu\u00f2 essere parallela solo se queste sezioni sono abbastanza grandi.<\/p>\n<p><\/p>\n<h3 id=\"parallelnoe-dopolnenie--parallel-append\">Appendice parallela \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> pu\u00f2 essere utilizzata al posto di diversi blocchi in diversi processi di lavoro. Di solito questo avviene con query UNION ALL. Il difetto \u00e8 che c'\u00e8 meno parallelismo, poich\u00e9 ogni processo di lavoro gestisce solo 1 query.<\/p>\n<p><\/p>\n<p>Qui sono in esecuzione 2 processi di lavoro, nonostante siano previsti 4.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">tpch=# spiega (costi disattivati) seleziona somma(l_quantity) come sum_qty da lineitem dove l_shipdate &lt;= data &#039;1998-12-01&#039; - intervallo &#039;105&#039; giorni unione tutto seleziona somma(l_quantity) come sum_qty da lineitem dove l_shipdate &lt;= data &#039;2000-12-01&#039; - intervallo &#039;105&#039; giorni;\n                                           PIANO DI QUERY\n------------------------------------------------------------------------------------------------\n Raccolta\n   Lavoratori Pianificati: 2\n   -&gt;  Appendice Parallela\n         -&gt;  Aggregato\n               -&gt;  Scansione Sequenziale su lineitem\n                     Filtro: (l_shipdate &lt;= &#039;2000-08-18 00:00:00&#039;::timestamp senza fuso orario)\n         -&gt;  Aggregato\n               -&gt;  Scansione Sequenziale su lineitem lineitem_1\n                     Filtro: (l_shipdate &lt;= &#039;1998-08-18 00:00:00&#039;::timestamp senza fuso orario)<\/code><\/pre>\n<p><\/p>\n<h3 id=\"samye-vazhnye-peremennye\">Le variabili pi\u00f9 importanti<\/h3>\n<p><\/p>\n<ul>\n<li>WORK_MEM limita la quantit\u00e0 di memoria per ogni processo, non solo per le query: work_mem <em> processi <\/em> connessioni = molta memoria.<\/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 quanti processi di lavoro utilizzer\u00e0 il programma in esecuzione per l'elaborazione parallela dal piano.<\/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 adatta il numero totale di processi di lavoro al numero di core della CPU sul 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 lo stesso, ma per i processi di lavoro paralleli.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"itogi\">Conclusioni<\/h3>\n<p><\/p>\n<p>A partire dalla versione 9.6, l'elaborazione parallela pu\u00f2 migliorare significativamente le prestazioni delle query complesse che esaminano molte righe o indici. In PostgreSQL 10, l'elaborazione parallela \u00e8 abilitata per impostazione predefinita. Ricorda di disabilitarla sui server con un carico di lavoro OLTP elevato. Le scansioni sequenziali o le scansioni degli indici consumano molte risorse. Se non stai eseguendo un report su tutto il set di dati, le query possono diventare pi\u00f9 efficienti semplicemente aggiungendo gli indici mancanti o utilizzando una corretta partizionamento.<\/p>\n<p><\/p>\n<h3 id=\"ssylki\">Link<\/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\">Parallelismo in PostgreSQL 11<\/a><\/noindex><\/li>\n<\/ul>\n<p>Fonte: <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\/it\/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=\"it_IT\" \/>\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\/it\/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\udd47Query parallele in PostgreSQL | ProHoster","description":"Nei processori moderni ci sono molti core.","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","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\/it\/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\/it\/wp-json\/wp\/v2\/posts\/30900","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=30900"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/30900\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media\/22879"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=30900"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=30900"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=30900"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}