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 tbl në csv me for dhe sed.
  5. Kloni depozita pg_tpch dhe kopjoni skedarët csv në pg_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+ mund tĂ« ekzekutojĂ« cikle tĂ« ngulitura nĂ« mĂ«nyrĂ« paralele — kjo Ă«shtĂ« njĂ« operacion i thjeshtĂ«.

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 '%specialposits%'
 group by c_custkey;
 PLANI I KËRKIMIT
--------------------------------------------------------------------------------------
 Finalizo Grup Agregat
 ÇelĂ«si i Grupit: customer.c_custkey
 -> Grumbull Mëre
 Punëtorët e Planifikuar: 4
 -> Grup Agregat të Pjesëmarrësve
 ÇelĂ«si i Grupit: customer.c_custkey
 -> Bashkim i Ngjitur në Nën (Left Join)
 -> Skanim i Indeksit Të Pjesëve Pjesë nga customer_pkey në customer
 -> Skanim Indeksi duke përdorur idx_orders_custkey në orders
 Kushti i Indeksit: (customer.c_custkey = o_custkey)
 Filtri: ((o_comment)::text !~~ '%specialposits%'::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 hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster