Kërkesa paralele në PostgreSQL

Kërkesa paralele në PostgreSQL
Në procesorët modernë ka shumë bërthama. Për vite me radhë, aplikacionet dërguan kërkesa në bazat e të dhënave në mënyrë paralel. Nëse kjo është një kërkesë raportuese për shumë rreshta në një tabelë, ajo ekzekutohet më shpejt kur angazhohen disa procesorë, dhe në PostgreSQL kjo është e mundur, që nga versioni 9.6.

Më mori 3 vjet për të zbatuar funksionin e kërkesave paralel — duhej të ri-shtypeshin kodet në faza të ndryshme të ekzekutimit të kërkesave. Në PostgreSQL 9.6 u shfaq infrastruktura për përmirësimin e mëtejshëm të kodit. Në versionet pasuese, edhe lloje të tjera të kërkesave ekzekutohen paralelisht.

Kufizimet

  • Mos aktivizoni ekzekutimin paralel nëse të gjithë bërthamat janë të angazhuara, përndryshe kërkesat e tjera do të ngadalësohen.
  • E rëndësishme, përpunimi paralel me vlera të larta WORK_MEM angazhon shumë memorie — çdo lidhje hash ose rregullim merr memorie për sa është work_mem.
  • Kërkesat OLTP me vonesë të ulët nuk mund të shpejtohen me ekzekutimin paralel. Dhe nëse kërkesa kthen një rresht, përpunimi paralel vetëm e ngadalëson atë.
  • Developerët e duan të përdorin benchmark-un TPC-H. Ndoshta keni kërkesa të ngjashme për ekzekutimin ideal paralel.
  • Vetëm kërkesat SELECT pa bllokimin e predikates ekzekutohen paralelisht.
  • Nganjëherë indeksimi i duhur është më i mirë se skanimi sekondar i tabelës në mënyrë paralel.
  • Pauzat e kërkesave dhe kursorët nuk mbështeten.
  • Funksionet e dritareve dhe funksionet agregate të grupeve të renditshme nuk janë paralel.
  • Nuk fitoni asgjë në ngarkesën e hyrjes-daljes.
  • Nuk ka algoritme paralel për renditje. Megjithatë, kërkesat me renditje mund të ekzekutohen paralelisht në disa aspekte.
  • Zëvendësoni CTE (ME ... ) me një SELECT të zhytur për të përfshirë përpunimin paralel.
  • Mbështetjet e të dhënave nga të tretët për momentin nuk mbështesin përpunimin paralel (por mund të ishin!)
  • FULL OUTER JOIN nuk mbështetet.
  • max_rows çaktivizon përpunimin paralel.
  • Nëse në kërkesë ka një funksion që nuk është e markuar si PARALLEL SAFE, ajo do të jetë një proces i vetëm.
  • Niveli i izolimit të trasaksioneve SERIALIZABLE çaktivizon përpunimin paralel.

Mjedisi i testimit

Developerët e PostgreSQL përpiqeshin të shkurtonin kohën e përgjigjeve të kërkesave të benchmark-ut TPC-H. Shkarkoni benchmark-un dhe përshtateni atë me PostgreSQL. Ky është një përdorim jozyrtar i benchmark-ut TPC-H — jo për krahasimin e bazave të të dhënave ose pajisjeve.

  1. Shkarkoni TPC-H_Tools_v2.17.3.zip (ose një version më të ri) nga faqja zyrtare TPC.
  2. Rinovoni makefile.suite në Makefile dhe ndryshoni siç përshkruhet këtu: https://github.com/tvondra/pg_tpch . Kompilon kodi me komandën make.
  3. Gjeneroni të dhënat: .\/dbgen -s 10 krijon një bazë të dhënash prej 23 GB. Kjo është e mjaftueshme për të parë diferencën në performancën e pyetjeve paralel dhe jo paralel.
  4. Konvertoni skedarët tblcsv me for dhe sed.
  5. Kloni depozita pg_tpch dhe kopjoni skedarët csvpg_tpch\/dss\/data.
  6. Krijoni pyetje me komandën qgen.
  7. Ngarkoni të dhënat në bazë me komandën .\/tpch.sh.

Skandimi paralel sekuencial

Ai mund të jetë më i shpejtë jo për shkak të leximit paralel, por sepse të dhënat janë shpërndarë mbi shumë bërthama CPU. Në sistemet operative moderne, skedarët e të dhënave PostgreSQL keq mësohen mirë. Me leximin parashikues, mund të merrni nga magazina një bllok më të madh se sa kërkon demon PG. Prandaj performanca e pyetjeve nuk pengohet nga I/O-i i diskut. Ai konsumon cikle CPU për të:

  • lexuar rreshta një nga një nga faqet e tabelës;
  • krahasuar vlerat e rreshtave dhe kushtet KU.

Le të ekzekutojmë një pyetje të thjeshtë select:

tpch=# shpjegoni analizën e zgjedhjes l_quantity si sum_qty nga lineitem ku l_shipdate <= data '1998-12-01' - interval '105' ditë;\nPLAN I PYETJES\n--------------------------------------------------------------------------------------------------------------------------\nSkanim Sekuencial mbi lineitem (kosto=0.00..1964772.00 rreshta=58856235 gjerësi=5) (koha reale=0.014..16951.669 rreshta=58839715 loops=1)\nFiltri: (l_shipdate <= '1998-08-18 00:00:00'::timestamp pa zonë kohe)\nRreshtat e hequr nga Filtri: 1146337\nKoha e Planifikimit: 0.203 ms\nKoha e Ekzekutimit: 19035.100 ms

Skandimi sekuencial jep shumë rreshta pa agregim, kështu që pyetja ekzekutohet nga një bërthamë CPU.

Nëse shtojmë SUM(), duket se dy procesorë do të ndihmojnë për të përshpejtuar pyetjen:

shpjegoni analizën e zgjedhjes sum(l_quantity) si sum_qty nga lineitem ku l_shipdate <= data '1998-12-01' - interval '105' ditë;\nPLAN I PYETJES\n----------------------------------------------------------------------------------------------------------------------------------------------------\nPërfundoni Agregat (kosto=1589702.14..1589702.15 rreshta=1 gjerësi=32) (koha reale=8553.365..8553.365 rreshta=1 loops=1)\n-> Grumbullo (kosto=1589701.91..1589702.12 rreshta=2 gjerësi=32) (koha reale=8553.241..8555.067 rreshta=3 loops=1)\nPunonjës të Planifikuar: 2\nPunonjës të Lëshuar: 2\n-> Agregat i Pjesës (kosto=1588701.91..1588701.92 rreshta=1 gjerësi=32) (koha reale=8547.546..8547.546 rreshta=1 loops=3)\n-> Skanim Paralel Sekuencial mbi lineitem (kosto=0.00..1527393.33 rreshta=24523431 gjerësi=5) (koha reale=0.038..5998.417 rreshta=19613238 loops=3)\nFiltri: (l_shipdate <= '1998-08-18 00:00:00'::timestamp pa zonë kohe)\nRreshtat e hequr nga Filtri: 382112\nKoha e Planifikimit: 0.241 ms\nKoha e Ekzekutimit: 8555.131 ms

Agregimi Paralel

Noda «Skani Paralel Sekuencial» prodhon rreshta për agregimin e pjesëve. Noda «Agregat i Pjesës» i pren rreshtat e këtyre me anë të SUM(). Në fund, numri i SUM nga çdo procesor grumbullohet nga noda «Grumbullo».

Rezultati përfundimtar llogariten nga nodi "Finalize Aggregate". Nëse keni funksione agregimi të tjera, mos harroni t'i shënoni ato si "parallel safe".

Numri i proceseve punuese

Numri i proceseve punuese mund të rritet pa rinisjen e serverit:

shpjegoni analizën e zgjedhjes sum(l_quantity) si sum_qty nga lineitem ku l_shipdate <= data '1998-12-01' - interval '105' ditë;\nPLAN I PYETJES\n----------------------------------------------------------------------------------------------------------------------------------------------------\nPërfundoni Agregat (kosto=1589702.14..1589702.15 rreshta=1 gjerësi=32) (koha reale=8553.365..8553.365 rreshta=1 loops=1)\n-> Grumbullo (kosto=1589701.91..1589702.12 rreshta=2 gjerësi=32) (koha reale=8553.241..8555.067 rreshta=3 loops=1)\nPunonjës të Planifikuar: 2\nPunonjës të Lëshuar: 2\n-> Agregat i Pjesës (kosto=1588701.91..1588701.92 rreshta=1 gjerësi=32) (koha reale=8547.546..8547.546 rreshta=1 loops=3)\n-> Skanim Paralel Sekuencial mbi lineitem (kosto=0.00..1527393.33 rreshta=24523431 gjerësi=5) (koha reale=0.038..5998.417 rreshta=19613238 loops=3)\nFiltri: (l_shipdate <= '1998-08-18 00:00:00'::timestamp pa zonë kohe)\nRreshtat e hequr nga Filtri: 382112\nKoha e Planifikimit: 0.241 ms\nKoha e Ekzekutimit: 8555.131 ms

Çfarë po ndodh këtu? Numri i proceseve punuese është dyfishuar, ndërsa kërkesa u bë vetëm 1,6599 herë më e shpejtë. Llogaritë janë interesante. Kishim 2 procese punuese dhe 1 lider. Pas ndryshimit, u bë 4+1.

Shpejtësia jonë maksimale nga përpunimi paralel: 5/3 = 1,66(6) herë.

Si funksionon kjo?

Proceset

Ekzekutimi i kërkesës gjithmonë fillon me procesin lider. Lideri bën të gjitha përpunimet jo-paralel dhe një pjesë të përpunimit paralel. Proceset e tjera, që kryejnë të njëjtat kërkesa, quhen procese punuese. Përpunimi paralel përdor infrastrukturën e proceseve punuese dinamike në sfond (nga versioni 9.4). Ndërsa pjesët e tjera të PostgreSQL përdorin procese dhe jo fije, një kërkesë me 3 procese punuese mund të jetë 4 herë më e shpejtë se përpunimi tradicional.

Ndërveprimi

Proceset punuese komunikojnë me liderin përmes një sistemi mesazhesh (për bazë të memories së përbashkët). Çdo proces ka 2 skeda: për gabimet dhe për tuple.

Sa procese punuese nevojiten?

Kufiri minimal vendoset nga parametri max_parallel_workers_per_gather. Pastaj ekzekutori i kërkesave merr proceset punuese nga rezervuari, i kufizuar nga parametri max_parallel_workers size. Kufiri i fundit është max_worker_processes, domethënë numri total i proceseve në sfond.

Nëse nuk arrihet të alokoni një proces punues, përpunimi do të jetë me proces të vetëm.

Planifikuesi i kërkesave mund të reduktojë proceset punuese në varësi të madhësisë së tabelës ose indekseve. Për këtë ka parametra min_parallel_table_scan_size dhe min_parallel_index_scan_size.

set min_parallel_table_scan_size='8MB' 8MB tabelë => 1 punues 24MB tabelë => 2 punues 72MB tabelë => 3 punues x => log(x / min_parallel_table_scan_size) / log(3) + 1 punues

Çdo herë që tabela është 3 herë më e madhe se min_parallel_(index|table)_scan_size, Postgres shton një proces punues. Numri i proceseve punuese nuk bazohet në kosto. Varësia ciklike e vështirëson realizimet e komplikuara. Në vend të kësaj, planifikuesi përdor rregulla të thjeshta.

Në praktikë, këto rregulla nuk janë gjithmonë të përshtatshme për prodhim, kështu që mund të ndryshoni numrin e proceseve punuese për një tabelë të caktuar: ALTER TABLE … SET (parallel_workers = N).

Pse nuk përdoret përpunimi paralel?

Përveç listës së gjatë të kufizimeve, ka edhe verifikime të shpenzimeve:

parallel_setup_cost — për të shmangur përpunimin paralel të kërkesave të shkurtra. Ky parametër vlerëson kohën për përgatitjen e memorjes, fillimin e procesit dhe shkëmbimin fillestar të të dhënave.

parallel_tuple_cost: komunikimi i liderit me punonjësit mund të zgjasë proporcionalisht me numrin e tuple-ve nga proceset punuese. Ky parametër llogarit shpenzimet për shkëmbimin e të dhënave.

Bashkimet e cikleve të thella — Nested Loop Join

PostgreSQL 9.6+ может выполнять вложенные циклы параллельно — это простая операция.

explain (costs off) select c_custkey, count(o_orderkey)
                from    customer left outer join orders on
                                c_custkey = o_custkey and o_comment not like '%special%deposits%'
                group by c_custkey;
                                      QUERY PLAN
--------------------------------------------------------------------------------------
 Finalize GroupAggregate
   Group Key: customer.c_custkey
   ->  Gather Merge
         Workers Planned: 4
         ->  Partial GroupAggregate
               Group Key: customer.c_custkey
               ->  Nested Loop Left Join
                     ->  Parallel Index Only Scan using customer_pkey on customer
                     ->  Index Scan using idx_orders_custkey on orders
                           Index Cond: (customer.c_custkey = o_custkey)
                           Filter: ((o_comment)::text !~~ '%special%deposits%'::text)

Grumbullimi ndodh në fazën e fundit, kështu që Nested Loop Left Join është një operacion paralel. Skano paralel vetëm mbi indekso u shfaq vetëm në versionin 10. Ai funksionon në mënyrë të ngjashme me skanimin paralel të rreshtave. Kushti c_custkey = o_custkey lexon një porosi për çdo rresht klienti. Pra, ai nuk është paralel.

Bashkimi me Hash — Hash Join

Çdo proces punues krijon tabelën e tij të hash deri në PostgreSQL 11. Dhe nëse ka më shumë se katër procese, performanca nuk do të rritet. Në versionin e ri, tabela e hash është e përbashkët. Çdo proces punues mund të përdorë WORK_MEM për të krijuar tabelën e hash.

zgjedh
        l_shipmode,
        shumë(rasti
                kur o_orderpriority = '1-URGENT'
                        ose o_orderpriority = '2-HIGH'
                        atëherë 1
                tjetër 0
        fund) si high_line_count,
        shumë(rasti
                kur o_orderpriority  '1-URGENT'
                        dhe o_orderpriority  '2-HIGH'
                        atëherë 1
                tjetër 0
        fund) si low_line_count
nga
        porositë,
        linjat
ku
        o_orderkey = l_orderkey
        dhe l_shipmode në ('MAIL', 'AIR')
        dhe l_commitdate < l_receiptdate
        dhe l_shipdate = data '1996-01-01'
        dhe l_receiptdate < data '1996-01-01' + interval '1' vit
grup në
        l_shipmode
rendit sipas
        l_shipmode
LIMIT 1;
                                                                                                                                    PLAN I KËRKESËS
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=1964755.66..1964961.44 rows=1 width=27) (actual time=7579.592..7922.997 rows=1 loops=1)
   ->  Finalizo Grupin e Agregatëve  (cost=1964755.66..1966196.11 rows=7 width=27) (actual time=7579.590..7579.591 rows=1 loops=1)
         Çelësi i Grupit: lineitem.l_shipmode
         ->  Grumbullo të Bashkuara  (cost=1964755.66..1966195.83 rows=28 width=27) (actual time=7559.593..7922.319 rows=6 loops=1)
               Punëtorët e Planifikuar: 4
               Punëtorët e Lëshuar: 4
               ->  Grumbullo të Pjesëshme  (cost=1963755.61..1965192.44 rows=7 width=27) (actual time=7548.103..7564.592 rows=2 loops=5)
                     Çelësi i Grupit: lineitem.l_shipmode
                     ->  Rendit  (cost=1963755.61..1963935.20 rows=71838 width=27) (actual time=7530.280..7539.688 rows=62519 loops=5)
                           Çelësi i Rendit: lineitem.l_shipmode
                           Metoda e Rendit: shpërndarje ekstreme  Disk: 2304kB
                           Punëtor 0:  Metoda e Rendit: shpërndarje ekstreme  Disk: 2064kB
                           Punëtor 1:  Metoda e Rendit: shpërndarje ekstreme  Disk: 2384kB
                           Punëtor 2:  Metoda e Rendit: shpërndarje ekstreme  Disk: 2264kB
                           Punëtor 3:  Metoda e Rendit: shpërndarje ekstreme  Disk: 2336kB
                           ->  Bashkimi i Hashit Paralel  (cost=382571.01..1957960.99 rows=71838 width=27) (actual time=7036.917..7499.692 rows=62519 loops=5)
                                 Kushti i Hashit: (lineitem.l_orderkey = orders.o_orderkey)
                                 ->  Skano nën grupin Paralel  (cost=0.00..1552386.40 rows=71838 width=19) (actual time=0.583..4901.063 rows=62519 loops=5)
                                       Filtri: ((l_shipmode = ÇDO ('{MAIL,AIR}'::bpchar[])) DHE (l_commitdate < l_receiptdate) DHE (l_shipdate = '1996-01-01'::date) DHE (l_receiptdate < '1997-01-01 00:00:00'::timestamp pa zonë të kohës))
                                       Rreshtat e Hequr nga Filtri: 11934691
                                 ->  Hash Paralel  (cost=313722.45..313722.45 rows=3750045 width=20) (actual time=2011.518..2011.518 rows=3000000 loops=5)
                                       Koshat: 65536  Grumbuj: 256  Përdorimi i Memorisë: 3840kB
                                       ->  Skano nën grupin Paralel  (cost=0.00..313722.45 rows=3750045 width=20) (actual time=0.029..995.948 rows=3000000 loops=5)
 Koha e Planifikimit: 0.977 ms
 Koha e Ekzekutimit: 7923.770 ms

Kërkesa 12 nga TPC-H ilustron qartë bashkimin e hashit paralel. Çdo proces punues merr pjesë në krijimin e një tabele të përbashkët hash.

Lidhja e bashkimit — Merge Join

Lidhja e bashkimit është natyrisht e pafavorshme për paralelizëm. Mos u shqetësoni nëse ky është hapi i fundit i pyetjes, ai mund të ekzekutohet gjithsesi paralelisht.

-- Kërkesa 2 nga TPC-H
shpjego (kostot off) zgjidh s_acctbal, s_name, n_name, p_partkey, p_mfgr, s_address, s_phone, s_comment
nga    part, supplier, partsupp, nation, region
ku
        p_partkey = ps_partkey
        dhe s_suppkey = ps_suppkey
        dhe p_size = 36
        dhe p_type si '%BRASS'
        dhe s_nationkey = n_nationkey
        dhe n_regionkey = r_regionkey
        dhe r_name = 'AMERICA'
        dhe ps_supplycost = (
                zgjidh
                        min(ps_supplycost)
                nga    partsupp, supplier, nation, region
                ku
                        p_partkey = ps_partkey
                        dhe s_suppkey = ps_suppkey
                        dhe s_nationkey = n_nationkey
                        dhe n_regionkey = r_regionkey
                        dhe r_name = 'AMERICA'
        )
rendit sipas s_acctbal zbret, n_name, s_name, p_partkey
KUFIZO 100;
                                                PLANI I KËRKESËS
----------------------------------------------------------------------------------------------------------
 Limit
   -&gt;  Rendit
         Çelësi i Rendit: supplier.s_acctbal ZBRET, nation.n_name, supplier.s_name, part.p_partkey
         -&gt;  Bashkimi i Shkrirë
               Kusht i Shkrirjes: (part.p_partkey = partsupp.ps_partkey)
               Filtri i Bashkimit: (partsupp.ps_supplycost = (SubPlani 1))
               -&gt;  Grumbullimi i Shkrirë
                     Punonjësit e Planifikuar: 4
                     -&gt;  Skano Indeksin Paralel duke përdorur <strong>part_pkey</strong> në pjesë
                           Filtri: (((p_type)::text ~~ '%BRASS'::text) DHE (p_size = 36))
               -&gt;  Materializo
                     -&gt;  Rendit
                           Çelësi i Rendit: partsupp.ps_partkey
                           -&gt;  Rrotullues i Foshnjave
                                 -&gt;  Rrotullues i Foshnjave
                                       Filtri i Bashkimit: (nation.n_regionkey = region.r_regionkey)
                                       -&gt;  Skano Sequentiellement mbi region
                                             Filtri: (r_name = 'AMERICA'::bpchar)
                                       -&gt;  Bashkimi Hash
                                             Kushti Hash: (supplier.s_nationkey = nation.n_nationkey)
                                             -&gt;  Skano Sequentiellement mbi supplier
                                             -&gt;  Hash
                                                   -&gt;  Skano Sequentiellement mbi nation
                                 -&gt;  Skano Indeksin duke përdorur idx_partsupp_suppkey mbi partsupp
                                       Kushti i Indeksit: (ps_suppkey = supplier.s_suppkey)
               SubPlani 1
                 -&gt;  Agregat
                       -&gt;  Rrotullues i Foshnjave
                             Filtri i Bashkimit: (nation_1.n_regionkey = region_1.r_regionkey)
                             -&gt;  Skano Sequentiellement mbi region region_1
                                   Filtri: (r_name = 'AMERICA'::bpchar)
                             -&gt;  Rrotullues i Foshnjave
                                   -&gt;  Rrotullues i Foshnjave
                                         -&gt;  Skano Indeksin duke përdorur idx_partsupp_partkey mbi partsupp partsupp_1
                                               Kushti i Indeksit: (part.p_partkey = ps_partkey)
                                         -&gt;  Skano Indeksin duke përdorur supplier_pkey mbi supplier supplier_1
                                               Kushti i Indeksit: (s_suppkey = partsupp_1.ps_suppkey)
                                   -&gt;  Skano Indeksin duke përdorur nation_pkey mbi nation nation_1
                                         Kushti i Indeksit: (n_nationkey = supplier_1.s_nationkey)

Noda «Merge Join» ndodhet mbi «Gather Merge». Pra, bashkimi nuk përdor përpunim paralel. Por noda «Parallel Index Scan» ndihmon prapë me segmentin part_pkey.

Lidhja sipas sekcioneve

Në PostgreSQL 11 lidhja sipas sekcioneve është e çaktivizuar si e paracaktuar: ka një planifikim shumë të shtrenjtë. Tabelat me sekcionim të ngjashëm mund të lidhen sekondë për sekondë. Kështu që Postgres do të përdorë tabela hesh të vogla. Çdo lidhje sekcionesh mund të jetë paralel.

tpch=# vendos enable_partitionwise_join=t;
tpch=# shpjego (kostot fikëse) zgjedh * nga prt1 t1, prt2 t2
ku t1.a = t2.b dhe t1.b = 0 dhe t2.b mes 0 dhe 10000;
                    PLANI I PYETJES
---------------------------------------------------
 Shtoni
   ->  Lidhja Hesh
         Kushti i Heshit: (t2.b = t1.a)
         ->  Skanoje Sequencialisht në prt2_p1 t2
               Filtri: ((b >= 0) DHE (b <= 10000))
         ->  Hesh
               ->  Skanoje Sequencialisht në prt1_p1 t1
                     Filtri: (b = 0)
   ->  Lidhja Hesh
         Kushti i Heshit: (t2_1.b = t1_1.a)
         ->  Skanoje Sequencialisht në prt2_p2 t2_1
               Filtri: ((b >= 0) DHE (b <= 10000))
         ->  Hesh
               ->  Skanoje Sequencialisht në prt1_p2 t1_1
                     Filtri: (b = 0)
tpch=# vendos parallel_setup_cost = 1;
tpch=# vendos parallel_tuple_cost = 0.01;
tpch=# shpjego (kostot fikëse) zgjedh * nga prt1 t1, prt2 t2
ku t1.a = t2.b dhe t1.b = 0 dhe t2.b mes 0 dhe 10000;
                        PLANI I PYETJES
-----------------------------------------------------------
 Mbledh
   Punonjësit e planifikuar: 4
   ->  Shtoni Paralel
         ->  Lidhja Hesh Paralel
               Kushti i Heshit: (t2_1.b = t1_1.a)
               ->  Skanoje Paralel në prt2_p2 t2_1
                     Filtri: ((b >= 0) DHE (b <= 10000))
               ->  Hesh
                     ->  Skanoje Paralel në prt1_p2 t1_1
                           Filtri: (b = 0)
         ->  Lidhja Hesh Paralel
               Kushti i Heshit: (t2.b = t1.a)
               ->  Skanoje Paralel në prt2_p1 t2
                     Filtri: ((b >= 0) DHE (b <= 10000))
               ->  Hesh
                     ->  Skanoje Paralel në prt1_p1 t1
                           Filtri: (b = 0)

E rëndësishme, lidhja sipas sekcioneve është paralel vetëm nëse këto sekcione janë të mjaftueshme të mëdha.

Shtimi Paralel — Parallel Append

Shtimi Paralel mund të përdoret në vend të blloqeve të ndryshme në procese të ndryshme. Kjo ndodh zakonisht me pyetje UNION ALL. Disavantazhi — më pak paralelizëm, pasi çdo proces punonjësi përpunon vetëm 1 pyetje.

Këtu janë nisur 2 proces punonjësish, megjithëse janë planifikuar 4.

tpch=# shpjego (costs off) përmbledh (sum) l_quantity as sum_qty nga lineitem ku l_shipdate <= data '1998-12-01' - interval '105' ditë union all përmbledh (sum) l_quantity as sum_qty nga lineitem ku l_shipdate   Shtim paralel
         ->  Agregatuar
               ->  Skanim sekuestrues në lineitem
                     Filtri: (l_shipdate   Agregatuar
               ->  Skanim sekuestrues në lineitem lineitem_1
                     Filtri: (l_shipdate <= '1998-08-18 00:00:00'::timestamp pa zonë kohore)

Variablat më të rëndësishëm

  • WORK_MEM kufizon sasinë e memories për secilin proces, jo vetëm për kërkesat: work_mem proceset lidhje = shumë memoria.
  • max_parallel_workers_per_gather — sa procese pune do të përdorë programi për procesimin paralel nga plani.
  • max_worker_processes — rregullon numrin total të punonjësve sipas numrit të bërthamave të CPU në server.
  • max_parallel_workers — po ashtu, por për proceset punuese paralel.

Përfundime

Fillimisht nga versioni 9.6, procesimi paralel mund të përmirësojë ndjeshëm performancën e kërkesave të komplikuara që skanojnë shumë rreshta ose indekse. Në PostgreSQL 10, procesimi paralel është aktivizuar si e drejtë. Mos harroni ta çaktivizoni në serverë me ngarkesë të madhe OLTP. Skanimet sekondare ose skanimet e indekseve konsumojnë shumë burime. Nëse nuk jeni në një raporton e të dhënave të plota, kërkesat mund të bëhen më efikase thjesht duke shtuar indekset që mungojnë ose duke përdorur ndarjen e duhur.

Linket

Burimi: habr.com

Blini hostim të besueshëm për faqe interneti me mbrojtje DDoS, serverë VPS VDS 🔥 Blini hostim të besueshëm për faqe interneti me mbrojtje DDoS, serverë VPS VDS - ProHoster