{"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\/pt\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","title":{"rendered":"Consultas paralelas no PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Consultas paralelas no PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/04\/bbb4b4d3f8714bbdb9b26ada2f2253b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nNos processadores modernos, existem muitos n\u00facleos. Durante anos, aplica\u00e7\u00f5es enviaram solicita\u00e7\u00f5es para bancos de dados em paralelo. Se \u00e9 uma solicita\u00e7\u00e3o de relat\u00f3rio para v\u00e1rias linhas em uma tabela, ela \u00e9 executada mais rapidamente quando utiliza v\u00e1rios processadores, e no PostgreSQL isso \u00e9 poss\u00edvel a partir da vers\u00e3o 9.6.<\/p>\n<p><\/p>\n<p>Foram necess\u00e1rios 3 anos para implementar a fun\u00e7\u00e3o de consultas paralelas \u2014 foi preciso reescrever o c\u00f3digo em diferentes etapas de execu\u00e7\u00e3o das consultas. Na vers\u00e3o 9.6 do PostgreSQL, surgiu a infraestrutura para melhorias adicionais no c\u00f3digo. Em vers\u00f5es posteriores, outros tipos de consultas tamb\u00e9m s\u00e3o executados em paralelo.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3 id=\"ogranicheniya\">Restri\u00e7\u00f5es<\/h3>\n<p><\/p>\n<ul>\n<li>N\u00e3o ative a execu\u00e7\u00e3o paralela se todos os n\u00facleos j\u00e1 estiverem ocupados, caso contr\u00e1rio, outras consultas ficar\u00e3o lentas.<\/li>\n<li>O mais importante, o processamento paralelo com valores elevados de WORK_MEM utiliza muita mem\u00f3ria \u2014 cada conex\u00e3o de hash ou ordena\u00e7\u00e3o consome mem\u00f3ria na quantidade de work_mem.<\/li>\n<li>Consultas OLTP com baixa lat\u00eancia n\u00e3o podem ser aceleradas por execu\u00e7\u00e3o paralela. E se a consulta retorna uma linha, o processamento paralelo s\u00f3 ir\u00e1 desaceler\u00e1-la.<\/li>\n<li>Os desenvolvedores gostam de usar o benchmark TPC-H. Talvez voc\u00ea tenha consultas semelhantes para execu\u00e7\u00e3o paralela ideal.<\/li>\n<li>Apenas consultas SELECT sem bloqueio de predicado s\u00e3o executadas em paralelo.<\/li>\n<li>\u00c0s vezes, a indexa\u00e7\u00e3o correta \u00e9 melhor do que a varredura sequencial da tabela em modo paralelo.<\/li>\n<li>Suspens\u00e3o de consultas e cursores n\u00e3o s\u00e3o suportados.<\/li>\n<li>Fun\u00e7\u00f5es de janela e fun\u00e7\u00f5es agregadas de conjuntos ordenados n\u00e3o s\u00e3o paralelas.<\/li>\n<li>Voc\u00ea n\u00e3o ganha nada na carga de trabalho de entrada e sa\u00edda.<\/li>\n<li>N\u00e3o existem algoritmos de ordena\u00e7\u00e3o paralela. Mas consultas com ordena\u00e7\u00f5es podem ser executadas em paralelo em alguns aspectos.<\/li>\n<li>Substitua CTE (WITH \u2026) por um SELECT aninhado para habilitar o processamento paralelo.<\/li>\n<li>Encapsulamentos de dados de terceiros ainda n\u00e3o suportam processamento paralelo (mas poderiam!)<\/li>\n<li>FULL OUTER JOIN n\u00e3o \u00e9 suportado.<\/li>\n<li>max_rows desabilita o processamento paralelo.<\/li>\n<li>Se a consulta contiver uma fun\u00e7\u00e3o n\u00e3o marcada como PARALLEL SAFE, ela ser\u00e1 unifio.<\/li>\n<li>O n\u00edvel de isolamento de transa\u00e7\u00e3o SERIALIZABLE desabilita o processamento paralelo.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"testovaya-sreda\">Ambiente de teste<\/h3>\n<p><\/p>\n<p>Os desenvolvedores do PostgreSQL tentaram reduzir o tempo de resposta das consultas do benchmark TPC-H. Baixe o benchmark e <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">adapte-o ao PostgreSQL<\/a><\/noindex>. Este \u00e9 um uso n\u00e3o oficial do benchmark TPC-H \u2014 n\u00e3o para compara\u00e7\u00e3o de bancos de dados ou hardware.<\/p>\n<p><\/p>\n<ol>\n<li>Baixe TPC-H_Tools_v2.17.3.zip (ou uma vers\u00e3o mais recente) <noindex><a rel=\"nofollow\" href=\"http:\/\/www.tpc.org\/tpc_documents_current_versions\/current_specifications.asp\">do site oficial do TPC<\/a><\/noindex>.<\/li>\n<li>Renomeie makefile.suite para Makefile e altere conforme descrito aqui: <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tvondra\/pg_tpch\">https:\/\/github.com\/tvondra\/pg_tpch <\/a><\/noindex>. Compile o c\u00f3digo usando o comando make.<\/li>\n<li>Gere os dados: <code>.\\\/dbgen -s 10<\/code> cria um banco de dados de 23 GB. Isso \u00e9 suficiente para observar a diferen\u00e7a no desempenho entre consultas paralelas e n\u00e3o paralelas.<\/li>\n<li>Converta os arquivos <code>tbl<\/code> em <code>csv com for<\/code> e <code>sed<\/code>.<\/li>\n<li>Clone o reposit\u00f3rio <code>pg_tpch<\/code> e copie os arquivos <code>csv<\/code> em <code>pg_tpch\\\/dss\\\/data<\/code>.<\/li>\n<li>Crie consultas com o comando <code>qgen<\/code>.<\/li>\n<li>Carregue os dados no banco com o comando <code>.\\\/tpch.sh<\/code>.<\/li>\n<\/ol>\n<p><\/p>\n<h3 id=\"parallelnoe-posledovatelnoe-skanirovanie\">Varredura sequencial paralela<\/h3>\n<p><\/p>\n<p>Ela pode ser mais r\u00e1pida n\u00e3o por causa da leitura paralela, mas porque os dados s\u00e3o distribu\u00eddos por muitos n\u00facleos de CPU. Em sistemas operacionais modernos, arquivos de dados do PostgreSQL s\u00e3o bem armazenados em cache. Com a leitura antecipada, \u00e9 poss\u00edvel obter do armazenamento um bloco maior do que o solicitado pelo daemon PG. Portanto, o desempenho da consulta n\u00e3o \u00e9 limitado pela entrada e sa\u00edda do disco. Ele consome ciclos de CPU para:<\/p>\n<p><\/p>\n<ul>\n<li>ler linhas uma a uma das p\u00e1ginas da tabela;<\/li>\n<li>comparar os valores das linhas e as condi\u00e7\u00f5es <code>WHERE<\/code>.<\/li>\n<\/ul>\n<p><\/p>\n<p>Vamos executar uma consulta simples <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 varredura sequencial fornece muitas linhas sem agrega\u00e7\u00e3o, portanto, a consulta \u00e9 executada em um \u00fanico n\u00facleo de CPU.<\/p>\n<p><\/p>\n<p>Se adicionar <code>SUM()<\/code>, \u00e9 poss\u00edvel ver que dois processos de trabalho ajudar\u00e3o a acelerar a consulta:<\/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\">Agrega\u00e7\u00e3o paralela<\/h3>\n<p><\/p>\n<p>O n\u00f3 &#171;Parallel Seq Scan&#187; gera linhas para agrega\u00e7\u00e3o parcial. O n\u00f3 &#171;Partial Aggregate&#187; reduz essas linhas utilizando <code>SUM()<\/code>. No final, o contador SUM de cada processo de trabalho \u00e9 coletado pelo n\u00f3 &#171;Gather&#187;.<\/p>\n<p><\/p>\n<p>O resultado final \u00e9 calculado pelo n\u00f3 &#171;Finalize Aggregate&#187;. Se voc\u00ea tiver suas pr\u00f3prias fun\u00e7\u00f5es de agrega\u00e7\u00e3o, n\u00e3o se esque\u00e7a de marc\u00e1-las como &#171;parallel safe&#187;.<\/p>\n<p><\/p>\n<h3 id=\"kolichestvo-rabochih-processov\">N\u00famero de processos de trabalho<\/h3>\n<p><\/p>\n<p>O n\u00famero de processos de trabalho pode ser aumentado sem reiniciar o servidor:<\/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>O que est\u00e1 acontecendo aqui? O n\u00famero de processos de trabalho dobrou, enquanto a requisi\u00e7\u00e3o ficou apenas 1,6599 vezes mais r\u00e1pida. Os c\u00e1lculos s\u00e3o interessantes. T\u00ednhamos 2 processos de trabalho e 1 l\u00edder. Ap\u00f3s a altera\u00e7\u00e3o, passamos a ter 4+1.<\/p>\n<p><\/p>\n<p>Nossa acelera\u00e7\u00e3o m\u00e1xima com processamento paralelo: 5\/3 = 1,66(6) vezes.<\/p>\n<p><\/p>\n<h2 id=\"kak-eto-rabotaet\">Como funciona?<\/h2>\n<p><\/p>\n<h3 id=\"processy\">Processos<\/h3>\n<p><\/p>\n<p>A execu\u00e7\u00e3o da requisi\u00e7\u00e3o sempre come\u00e7a com o processo l\u00edder. O l\u00edder realiza toda a parte n\u00e3o paralela e parte do processamento paralelo. Os outros processos que executam as mesmas requisi\u00e7\u00f5es s\u00e3o chamados de processos de trabalho. O processamento paralelo utiliza a infraestrutura <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/11\/bgworker.html\">de processos de trabalho em segundo plano din\u00e2micos<\/a><\/noindex> (desde a vers\u00e3o 9.4). Como outras partes do PostgreSQL utilizam processos e n\u00e3o threads, uma requisi\u00e7\u00e3o com 3 processos de trabalho poderia ser at\u00e9 4 vezes mais r\u00e1pida que o processamento tradicional.<\/p>\n<p><\/p>\n<h3 id=\"vzaimodeystvie\">Intera\u00e7\u00e3o<\/h3>\n<p><\/p>\n<p>Os processos de trabalho se comunicam com o l\u00edder atrav\u00e9s de uma fila de mensagens (baseada em mem\u00f3ria compartilhada). Cada processo tem 2 filas: para erros e para tuplas.<\/p>\n<p><\/p>\n<h3 id=\"skolko-nuzhno-rabochih-processov\">Quantos processos de trabalho s\u00e3o necess\u00e1rios?<\/h3>\n<p><\/p>\n<p>O limite m\u00ednimo \u00e9 definido pelo par\u00e2metro <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>. Em seguida, o executor de requisi\u00e7\u00f5es obt\u00e9m os processos de trabalho do pool, limitado pelo par\u00e2metro <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>. O \u00faltimo limite \u00e9 o <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>, ou seja, o n\u00famero total de processos em segundo plano.<\/p>\n<p><\/p>\n<p>Se n\u00e3o for poss\u00edvel alocar um processo de trabalho, o processamento ser\u00e1 feito de forma sequencial.<\/p>\n<p><\/p>\n<p>O planejador de requisi\u00e7\u00f5es pode reduzir o n\u00famero de processos de trabalho com base no tamanho da tabela ou do \u00edndice. Para isso, existem os par\u00e2metros <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 tabela =&gt; 1 trabalhador\n24MB tabela =&gt; 2 trabalhadores\n72MB tabela =&gt; 3 trabalhadores\nx =&gt; log(x \/ min_parallel_table_scan_size) \/ log(3) + 1 trabalhador<\/code><\/pre>\n<p><\/p>\n<p>Cada vez que a tabela \u00e9 3 vezes maior que <code>min_parallel_(index|table)_scan_size<\/code>, o Postgres adiciona um processo de trabalho. O n\u00famero de processos de trabalho n\u00e3o se baseia em custos. A depend\u00eancia circular dificulta implementa\u00e7\u00f5es complexas. Em vez disso, o planejador utiliza regras simples.<\/p>\n<p><\/p>\n<p>Na pr\u00e1tica, essas regras nem sempre s\u00e3o adequadas para ambientes de produ\u00e7\u00e3o, ent\u00e3o \u00e9 poss\u00edvel alterar o n\u00famero de processos de trabalho para uma tabela espec\u00edfica: ALTER TABLE \u2026 SET (<code>parallel_workers = N<\/code>).<\/p>\n<p><\/p>\n<h3 id=\"pochemu-parallelnaya-obrabotka-ne-ispolzuetsya\">Por que o processamento paralelo n\u00e3o \u00e9 utilizado?<\/h3>\n<p><\/p>\n<p>Al\u00e9m de uma longa lista de limita\u00e7\u00f5es, existem tamb\u00e9m verifica\u00e7\u00f5es de custo:<\/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 para evitar o processamento paralelo de consultas curtas. Este par\u00e2metro estima o tempo para preparar a mem\u00f3ria, iniciar o processo e realizar a troca inicial de dados.<\/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>: a comunica\u00e7\u00e3o do l\u00edder com os trabalhadores pode se prolongar proporcionalmente ao n\u00famero de tuplas dos processos de trabalho. Este par\u00e2metro calcula os custos de troca de dados.<\/p>\n<p><\/p>\n<h3 id=\"soedineniya-vlozhennyh-ciklov--nested-loop-join\">Jun\u00e7\u00e3o de La\u00e7os Aninhados \u2014 Nested Loop Join<\/h3>\n<p><\/p>\n<pre><code class=\"plaintext\">O PostgreSQL 9.6+ pode executar ciclos aninhados em paralelo \u2014 \u00e9 uma opera\u00e7\u00e3o simples.\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 Finalizar GroupAggregate\n Chave do Grupo: customer.c_custkey\n -&gt; Reunir Merge\n Trabalhadores Planejados: 4\n -&gt; GroupAggregate Parcial\n Chave do Grupo: customer.c_custkey\n -&gt; Jun\u00e7\u00e3o \u00e0 Esquerda com Loop Aninhado\n -&gt; Digitaliza\u00e7\u00e3o de \u00cdndice Apenas Paralela usando customer_pkey em customer\n -&gt; Digitaliza\u00e7\u00e3o de \u00cdndice usando idx_orders_custkey em orders\n Condi\u00e7\u00e3o do \u00cdndice: (customer.c_custkey = o_custkey)\n Filtro: ((o_comment)::text !~~ '%specialposits%'::text)<\/code><\/pre>\n<p><\/p>\n<p>A coleta acontece na \u00faltima fase, ent\u00e3o a Jun\u00e7\u00e3o de La\u00e7os Aninhados \u2014 Nested Loop Left Join \u2014 \u00e9 uma opera\u00e7\u00e3o paralela. O Parallel Index Only Scan apareceu apenas na vers\u00e3o 10. Ele funciona de maneira semelhante ao escaneamento sequencial paralelo. A condi\u00e7\u00e3o <code>c_custkey = o_custkey<\/code> l\u00ea uma ordem para cada linha de cliente. Portanto, n\u00e3o \u00e9 paralelo.<\/p>\n<p><\/p>\n<h3 id=\"hesh-soedinenie--hash-join\">Jun\u00e7\u00e3o de Hash \u2014 Hash Join<\/h3>\n<p><\/p>\n<p>Antes do PostgreSQL 11, cada processo de trabalho criava sua pr\u00f3pria tabela de hash. E se houver mais de quatro desses processos, o desempenho n\u00e3o aumenta. Na nova vers\u00e3o, a tabela de hash \u00e9 compartilhada. Cada processo de trabalho pode usar WORK_MEM para criar uma tabela de hash.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">selecione\n        l_shipmode,\n        somat\u00f3rio(caso\n                quando o_orderpriority = '1-URGENTE'\n                        ou o_orderpriority = '2-ALTO'\n                        ent\u00e3o 1\n                sen\u00e3o 0\n        fim) como high_line_count,\n        somat\u00f3rio(caso\n                quando o_orderpriority  '1-URGENTE'\n                        e o_orderpriority  '2-ALTO'\n                        ent\u00e3o 1\n                sen\u00e3o 0\n        fim) como low_line_count\nde\n        orders,\n        lineitem\nonde\n        o_orderkey = l_orderkey\n        e l_shipmode em ('MAIL', 'AIR')\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; + intervalo &#039;1&#039; ano\ngrupo por\n        l_shipmode\nordem por\n        l_shipmode\nLIMIT 1;\n                                                                                                                                    PLANO DE CONSULTA\n-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n Limite  (custo=1964755.66..1964961.44 linhas=1 largura=27) (tempo real=7579.592..7922.997 linhas=1 la\u00e7os=1)\n   -&gt;  Finalizar GroupAggregate  (custo=1964755.66..1966196.11 linhas=7 largura=27) (tempo real=7579.590..7579.591 linhas=1 la\u00e7os=1)\n         Chave do Grupo: lineitem.l_shipmode\n         -&gt;  Jun\u00e7\u00e3o de Reuni\u00e3o  (custo=1964755.66..1966195.83 linhas=28 largura=27) (tempo real=7559.593..7922.319 linhas=6 la\u00e7os=1)\n               Trabalhadores Planejados: 4\n               Trabalhadores Lan\u00e7ados: 4\n               -&gt;  GroupAggregate Parcial  (custo=1963755.61..1965192.44 linhas=7 largura=27) (tempo real=7548.103..7564.592 linhas=2 la\u00e7os=5)\n                     Chave do Grupo: lineitem.l_shipmode\n                     -&gt;  Classifica\u00e7\u00f5es  (custo=1963755.61..1963935.20 linhas=71838 largura=27) (tempo real=7530.280..7539.688 linhas=62519 la\u00e7os=5)\n                           Chave de Classifica\u00e7\u00e3o: lineitem.l_shipmode\n                           M\u00e9todo de Classifica\u00e7\u00e3o: mesclagem externa  Disco: 2304kB\n                           Trabalhador 0:  M\u00e9todo de Classifica\u00e7\u00e3o: mesclagem externa  Disco: 2064kB\n                           Trabalhador 1:  M\u00e9todo de Classifica\u00e7\u00e3o: mesclagem externa  Disco: 2384kB\n                           Trabalhador 2:  M\u00e9todo de Classifica\u00e7\u00e3o: mesclagem externa  Disco: 2264kB\n                           Trabalhador 3:  M\u00e9todo de Classifica\u00e7\u00e3o: mesclagem externa  Disco: 2336kB\n                           -&gt;  Jun\u00e7\u00e3o Hash Paralela  (custo=382571.01..1957960.99 linhas=71838 largura=27) (tempo real=7036.917..7499.692 linhas=62519 la\u00e7os=5)\n                                 Condi\u00e7\u00e3o Hash: (lineitem.l_orderkey = orders.o_orderkey)\n                                 -&gt;  Varredura Sequencial Paralela sobre lineitem  (custo=0.00..1552386.40 linhas=71838 largura=19) (tempo real=0.583..4901.063 linhas=62519 la\u00e7os=5)\n                                       Filtro: ((l_shipmode = QUALQUER (&#039;{MAIL,AIR}&#039;::bpchar[])) E (l_commitdate &lt; l_receiptdate) E (l_shipdate = '1996-01-01'::date) E (l_receiptdate &lt; &#039;1997-01-01 00:00:00&#039;::timestamp sem fuso hor\u00e1rio))\n                                       Linhas Removidas pelo Filtro: 11934691\n                                 -&gt;  Hash Paralela  (custo=313722.45..313722.45 linhas=3750045 largura=20) (tempo real=2011.518..2011.518 linhas=3000000 la\u00e7os=5)\n                                       Baldes: 65536  Lotes: 256  Uso de Mem\u00f3ria: 3840kB\n                                       -&gt;  Varredura Sequencial Paralela sobre orders  (custo=0.00..313722.45 linhas=3750045 largura=20) (tempo real=0.029..995.948 linhas=3000000 la\u00e7os=5)\n Tempo de Planejamento: 0.977 ms\n Tempo de Execu\u00e7\u00e3o: 7923.770 ms<\/code><\/pre>\n<p><\/p>\n<p>A Consulta 12 do TPC-H mostra claramente uma jun\u00e7\u00e3o hash paralela. Cada worker participa na cria\u00e7\u00e3o de uma tabela hash global.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-sliyaniem--merge-join\">Jun\u00e7\u00e3o de Mesclagem \u2014 Merge Join<\/h3>\n<p><\/p>\n<p>A jun\u00e7\u00e3o de mesclagem \u00e9 n\u00e3o paralela por natureza. N\u00e3o se preocupe se esta for a \u00faltima etapa da consulta, pois ela ainda pode ser executada em paralelo.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">-- Consulta 2 do TPC-H\nexplique (custos desativados) selecione 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;AM&Eacute;RICA&#039;\n        and ps_supplycost = (\n                selecione\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;AM&Eacute;RICA&#039;\n        )\norder by s_acctbal desc, n_name, s_name, p_partkey\nLIMIT 100;\n                                                PLANO DA CONSULTA\n----------------------------------------------------------------------------------------------------------\n Limite\n   -&amp;gt;  Ordenar\n         Chave de Ordena&ccedil;&atilde;o: supplier.s_acctbal DESC, nation.n_name, supplier.s_name, part.p_partkey\n         -&amp;gt;  Jun&ccedil;&atilde;o de Mesclagem\n               Condi&ccedil;&atilde;o de Mesclagem: (part.p_partkey = partsupp.ps_partkey)\n               Filtro de Jun&ccedil;&atilde;o: (partsupp.ps_supplycost = (SubPlano 1))\n               -&amp;gt;  Coletar Mesclagem\n                     Trabalhadores Planejados: 4\n                     -&amp;gt;  Varredura de &Iacute;ndice Paralela usando &lt;strong&gt;part_pkey&lt;\/strong&gt; em parte\n                           Filtro: (((p_type)::text ~~ &#039;%BRASS&#039;::text) E (p_size = 36))\n               -&amp;gt;  Materializar\n                     -&amp;gt;  Ordenar\n                           Chave de Ordena&ccedil;&atilde;o: partsupp.ps_partkey\n                           -&amp;gt;  La&ccedil;o Aninhado\n                                 -&amp;gt;  La&ccedil;o Aninhado\n                                       Filtro de Jun&ccedil;&atilde;o: (nation.n_regionkey = region.r_regionkey)\n                                       -&amp;gt;  Varredura Sequencial na regi&atilde;o\n                                             Filtro: (r_name = &#039;AM&Eacute;RICA&#039;::bpchar)\n                                       -&amp;gt;  Jun&ccedil;&atilde;o por Hash\n                                             Condi&ccedil;&atilde;o de Hash: (supplier.s_nationkey = nation.n_nationkey)\n                                             -&amp;gt;  Varredura Sequencial no fornecedor\n                                             -&amp;gt;  Hash\n                                                   -&amp;gt;  Varredura Sequencial na na&ccedil;&atilde;o\n                                 -&amp;gt;  Varredura de &Iacute;ndice usando idx_partsupp_suppkey em partsupp\n                                       Condi&ccedil;&atilde;o de &Iacute;ndice: (ps_suppkey = supplier.s_suppkey)\n               SubPlano 1\n                 -&amp;gt;  Agregar\n                       -&amp;gt;  La&ccedil;o Aninhado\n                             Filtro de Jun&ccedil;&atilde;o: (nation_1.n_regionkey = region_1.r_regionkey)\n                             -&amp;gt;  Varredura Sequencial na regi&atilde;o region_1\n                                   Filtro: (r_name = &#039;AM&Eacute;RICA&#039;::bpchar)\n                             -&amp;gt;  La&ccedil;o Aninhado\n                                   -&amp;gt;  La&ccedil;o Aninhado\n                                         -&amp;gt;  Varredura de &Iacute;ndice usando idx_partsupp_partkey em partsupp partsupp_1\n                                               Condi&ccedil;&atilde;o de &Iacute;ndice: (part.p_partkey = ps_partkey)\n                                         -&amp;gt;  Varredura de &Iacute;ndice usando supplier_pkey em supplier supplier_1\n                                               Condi&ccedil;&atilde;o de &Iacute;ndice: (s_suppkey = partsupp_1.ps_suppkey)\n                                   -&amp;gt;  Varredura de &Iacute;ndice usando nation_pkey em nation nation_1\n                                         Condi&ccedil;&atilde;o de &Iacute;ndice: (n_nationkey = supplier_1.s_nationkey)<\/code><\/pre>\n<p><\/p>\n<p>O n\u00f3 &#171;Merge Join&#187; est\u00e1 acima do &#171;Gather Merge&#187;. Assim, a jun\u00e7\u00e3o n\u00e3o utiliza processamento paralelo. Mas o n\u00f3 &#171;Parallel Index Scan&#187; ainda ajuda com o segmento. <code>part_pkey<\/code>.<\/p>\n<p><\/p>\n<h3 id=\"soedinenie-po-sekciyam\">Jun\u00e7\u00e3o por Se\u00e7\u00f5es<\/h3>\n<p><\/p>\n<p>No PostgreSQL 11 <noindex><a rel=\"nofollow\" href=\"http:\/\/ashutoshpg.blogspot.com\/2017\/12\/partition-wise-joins-divide-and-conquer.html\">jun\u00e7\u00e3o por se\u00e7\u00f5es<\/a><\/noindex> desativado por padr\u00e3o: seu agendamento \u00e9 muito custoso. Tabelas com particionamentos semelhantes podem ser unidas se\u00e7\u00e3o por se\u00e7\u00e3o. Assim, o Postgres usar\u00e1 tabelas hash menores. Cada jun\u00e7\u00e3o de se\u00e7\u00f5es pode ser paralela.<\/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>Principalmente, a jun\u00e7\u00e3o por se\u00e7\u00f5es pode ser paralela, apenas se essas se\u00e7\u00f5es forem grandes o suficiente.<\/p>\n<p><\/p>\n<h3 id=\"parallelnoe-dopolnenie--parallel-append\">Anexo Paralelo \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> pode ser utilizado em vez de diferentes blocos em diferentes processos de trabalho. Normalmente, isso acontece com consultas UNION ALL. A desvantagem \u00e9 a menor paraleliza\u00e7\u00e3o, pois cada processo de trabalho processa apenas 1 consulta.<\/p>\n<p><\/p>\n<p>Aqui, 2 processos de trabalho foram iniciados, embora 4 tenham sido ativados.<\/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\">As vari\u00e1veis mais importantes<\/h3>\n<p><\/p>\n<ul>\n<li>WORK_MEM limita a quantidade de mem\u00f3ria para cada processo, n\u00e3o apenas para as consultas: work_mem <em> processos <\/em> conex\u00f5es = muita mem\u00f3ria.<\/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 quantos processos trabalhistas o programa em execu\u00e7\u00e3o usar\u00e1 para o processamento paralelo a partir do plano.<\/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 ajusta o n\u00famero total de processos trabalhistas com base no n\u00famero de n\u00facleos de CPU no servidor.<\/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 o mesmo, mas para processos trabalhistas paralelos.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"itogi\">Resultados<\/h3>\n<p><\/p>\n<p>A partir da vers\u00e3o 9.6, o processamento paralelo pode melhorar significativamente o desempenho de consultas complexas que escaneiam muitas linhas ou \u00edndices. No PostgreSQL 10, o processamento paralelo \u00e9 habilitado por padr\u00e3o. N\u00e3o se esque\u00e7a de desativ\u00e1-lo em servidores com alta carga de trabalho OLTP. Escaneamentos sequenciais ou de \u00edndices consomem muitos recursos. Se voc\u00ea n\u00e3o estiver executando um relat\u00f3rio sobre um conjunto de dados completo, as consultas podem ser mais eficientes, simplesmente adicionando os \u00edndices ausentes ou usando particionamento adequado.<\/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\">Paralelismo no 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.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\/pt\/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=\"pt_PT\" \/>\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\/pt\/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\udd47 Consultas paralelas no PostgreSQL | ProHoster","description":"Em CPUs modernas, h\u00e1 muitos n\u00facleos.","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/parallelnye-zaprosy-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","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\/pt\/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\/pt\/wp-json\/wp\/v2\/posts\/30900","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=30900"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/30900\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media\/22879"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=30900"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=30900"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=30900"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}