sql >> Database teknologi >  >> RDS >> Database

Sådan starter parallelle planer - del 4

Dette er den fjerde del i en serie i fem dele, der tager et dybt dyk ned i den måde, hvorpå parallelle planer i SQL Server-rækketilstand begynder at blive eksekveret. Del 1 initialiserede udførelseskontekst nul for den overordnede opgave, og del 2 oprettede forespørgselsscanningstræet. Del 3 startede forespørgselsscanningen, udførte en tidlig fase behandling, og startede de første ekstra parallelle opgaver i gren C.

Udførelsesdetaljer for filial C

Dette er det andet trin i udførelsessekvensen:

  1. Afdeling A (overordnet opgave).
  2. Gren C (yderligere parallelle opgaver).
  3. Afdeling D (yderligere parallelle opgaver).
  4. Afdeling B (yderligere parallelle opgaver).

En påmindelse om grenene i vores parallelplan (klik for at forstørre)

Kort tid efter de nye opgaver for filial C er i kø, vedhæfter SQL Server en arbejder til hver opgave og placerer arbejderen på en planlægger klar til udførelse. Hver ny opgave kører i en ny udførelseskontekst. På DOP 2 er der to nye opgaver, to arbejdstråde og to udførelseskontekster for gren C. Hver opgave kører sin egen kopi af iteratorerne i gren C på sin egen arbejdstråd:

De to nye parallelle opgaver begynder at køre ved en underprocedure indgangspunkt, som i første omgang fører til en Open ring til producentsiden af ​​børsen (CQScanXProducerNew::Open ). Begge opgaver har identiske opkaldsstabler i starten af ​​deres liv:

Udvekslingssynkronisering

I mellemtiden er overordnet opgave (kører på sin egen arbejdstråd) registrerer de nye underprocesser hos underprocesadministratoren og venterforbrugersiden af ompartitionsstrømmene udveksles ved node 5. Den overordnede opgave venter på CXPACKET * indtil alle af gren C parallelle opgaver fuldfør deres Open opkald og vende tilbage til producentsiden af ​​centralen. De parallelle opgaver åbner hver iterator i deres undertræ (dvs. ned til indekssøgningen ved node 9 og tilbage), før de vender tilbage til genopdelingsstrømudvekslingen ved node 5. Den overordnede opgave vil vente på CXPACKET mens dette sker. Husk, at den overordnede opgave udfører opkald i den tidlige fase.

Vi kan se denne ventetid i de ventende opgaver DMV:

Eksekveringskontekst nul (overordnet opgave) er blokeret af begge de nye eksekveringskontekster. Disse udførelseskontekster er de første ekstra, der oprettes efter kontekst nul, så de tildeles numrene et og to. For at understrege:Begge nye udførelseskontekster skal åbne deres undertræer og vende tilbage til udvekslingen for den overordnede opgaves CXPACKET vent til ende.

Du havde måske forventet at se CXCONSUMER venter her, men den ventetid er reserveret til at vente på rækkedata at ankomme. Den aktuelle ventetid er ikke for rækker — det er op til producentsiden at åbne , så vi får en generisk CXPACKET *vent.

* Azure SQL Database og Managed Instance bruger den nye CXSYNC_PORT vent i stedet for CXPACKET her, men den forbedring har endnu ikke fundet vej til SQL Server (fra 2019 CU9).

Inspicering af de nye parallelle opgaver

Vi kan se de nye opgaver i forespørgselsprofilerne DMV. Profileringsoplysninger for de nye opgaver vises i DMV'en, fordi deres udførelseskontekster blev afledt (klonet og derefter opdateret) fra det overordnede (udførelseskontekst nul):

Der er nu tre poster for hver iterator i gren C (fremhævet). En for den overordnede opgave (udførelseskontekst nul), og en for hver ny ekstra parallel opgave (kontekst 1 og 2). Bemærk, at den estimerede række pr. tråd tæller (se del 1) er ankommet nu, og vises kun for de parallelle opgaver. Den første og sidste aktive tid for de parallelle opgaver repræsenterer det tidspunkt, hvor deres udførelseskontekster blev skabt. Ingen af ​​de nye opgaver er åbnet nogen iteratorer endnu.

omopdelingsstrømmene udveksling ved node 5 har stadig kun en enkelt indgang i DMV-udgangen. Dette skyldes, at den tilknyttede usynlige profiler overvåger forbrugeren side af udvekslingen. De yderligere parallelle opgaver ligger hos producenten side af udvekslingen. Forbrugersiden af ​​node 5 vil efterhånden har parallelle opgaver, men vi er ikke nået dertil endnu.

Checkpoint

Dette virker som et godt punkt til at holde pause for at trække vejret og opsummere, hvor alt er i øjeblikket. Der vil være flere af disse stoppunkter, efterhånden som vi går.

  • Den overordnede opgave er på forbrugersiden af ompartitionsstrømmene udveksles ved node 5 , venter på CXPACKET . Det er midt i udførelsen af ​​opkald i de tidlige faser. Den holdt pause for at starte gren C, fordi den gren indeholder en blokerende sortering. Den overordnede opgaves ventetid vil fortsætte, indtil begge parallelle opgaver afslutter åbningen af ​​deres undertræer.
  • To nye parallelle opgaverproducentsiden af node 5-udvekslingen er klar til at åbne iteratorerne i gren C.

Intet uden for Branch C i denne parallelle eksekveringsplan kan gøre fremskridt, før den overordnede opgave er frigivet fra dens CXPACKET vente. Husk, at vi kun har oprettet ét sæt yderligere parallelle arbejdere indtil videre til gren C. Den eneste anden tråd er overordnet opgave, og den er blokeret.

Branch C Parallel Execution

De to parallelle opgaver starter på producentsiden af opdelingsstrømmene udveksles ved node 5. Hver har en separat (seriel) plan med sin egen strømaggregat, sortering og indekssøgning. Beregningsskalaren vises ikke i køretidsplanen, fordi dens beregninger er udskudt til sorteringen.

Hver forekomst af indekssøgningen er parallel-bevidst og fungerer på usammenhængende sæt rækker. Disse sæt genereres efter behov fra det overordnede rækkesæt, der er oprettet tidligere af den overordnede opgave (dækket i del 1). Når en af ​​forekomsterne af søgningen har brug for et nyt underområde af rækker, synkroniseres det med de andre arbejdertråde, så kun én tildeler et nyt underområde på samme tid. Det anvendte synkroniseringsobjekt blev også oprettet tidligere af den overordnede opgave. Når en opgave venter på eksklusiv adgang til det overordnede rækkesæt for at erhverve et nyt underområde, venter den på CXROWSET_SYNC .

Afdeling C-opgaver åbne

Sekvensen af ​​Open opkald for hver opgave i gren C er:

  • CQScanXProducerNew::Open . Bemærk, at der ikke er nogen forudgående profiler på producentsiden af ​​en børs. Dette er uheldigt for forespørgselstunere.
  • CXTransLocal::Open
  • CXPort::Register
  • CXTransLocal::ActivateWorkers
  • CQScanProfileNew::Open . Profileren over node 6.
  • CQScanStreamAggregateNew::Open (node ​​6)
  • CQScanProfileNew::Open . Profileren over node 7.
  • CQScanSortNew::Open (node ​​7)

Sorten er en fuldstændig blokerende operatør . Den bruger hele sin input under dens Open opkald. Der er et stort antal interessante interne detaljer at udforske her, men pladsen er knap, så jeg vil kun dække højdepunkterne:

sorteringen bygger sin sorteringstabel ved at åbne dens undertræ og forbruge alle de rækker, dens børn kan levere. Når sorteringen er fuldført, er sorteringen klar til at gå over til outputtilstand, og den returnerer kontrollen til sin overordnede. Sorteringen vil senere reagere på GetRow() opkald og returnerer den næste sorterede række hver gang. En illustrativ opkaldsstak under sorteringsinput er:

Udførelsen fortsætter, indtil hver sortering har opbrugt alle de (usammenhængende rækker af) rækker, der er tilgængelige fra dens underordnede indekssøgning . Sorteringerne kalder derefter Close på indekssøgningerne og returnerer kontrollen til deres overordnede streamaggregat . Strømaggregaterne initialiserer deres tællere og returnerer kontrollen til producenten side af ompartitionsudvekslingen ved node 5. Sekvensen Open opkald er nu afsluttet i denne gren.

Profilerings-DMV'en viser på dette tidspunkt opdaterede timingtal og lukketider for parallelindekset søger:

Mere udvekslingssynkronisering

Husk, at forældreopgaven venter på forbrugeren side af node 5 for alle producenter at åbne. En lignende synkroniseringsproces sker nu blandt de parallelle opgaver på producenten side af samme udveksling:

Hver producentopgave synkroniseres med de andre via CXTransLocal::Synchronize . Producenterne kalder CXPort::Open , vent derefter på CXPACKET for alle forbrugersiden parallelle opgaver at åbne. Når den første parallelopgave i Branch C ankommer tilbage til producentsiden af ​​børsen og venter, ser venteopgaverne DMV således ud:

Vi har stadig forældreopgavens ventetider på forbrugersiden. Den nye CXPACKET fremhævet er vores første parallelle opgave på producentsiden, der venter på alle parallelle opgaver på forbrugersiden for at åbne udvekslingsporten.

De parallelle opgaver på forbrugersiden (i Branch B) eksisterer ikke engang endnu, så producentopgaven viser NULL for den eksekveringskontekst, den er blokeret af. Opgaven, der i øjeblikket venter på forbrugersiden af ​​ompartitionsstrømudvekslingen, er den overordnede opgave (ikke en parallel opgave!), der kører EarlyPhases kode, så det tæller ikke.

Overordnet opgave CXPACKET vente slutter

Når den anden parallel opgave i Branch C ankommer tilbage til producentsiden af ​​børsen fra dens Open opkald, har alle producenter åbnet udvekslingsporten, så forælderopgavenforbrugersiden af udvekslingen er frigivet fra dens CXPACKET vent.

Arbejderne på producentsiden fortsætter med at vente på, at forbrugersidens parallelle opgaver bliver oprettet og åbner udvekslingsporten:

Checkpoint

På dette tidspunkt:

  • Der er i alt tre opgaver:To i gren C, plus den overordnede opgave.
  • Begge producenter ved node 5 er centralen åbnet og venterCXPACKET for at åbne parallelle opgaver på forbrugersiden. Meget af udvekslingsmaskineriet (inklusive rækkebuffere) er skabt af forbrugersiden, så der er ingen steder for producenterne at lægge rækker endnu.
  • De sorter i gren C har brugt alt deres input og er klar til at levere sorteret output.
  • Indekssøgningerne i afdeling C har afsluttet deres arbejde og lukket ned.
  • Den overordnede opgave er netop blevet frigivet fra at vente på CXPACKET på forbrugersiden af ​​noden 5 udveksler opdelingsstrømme. Det er stadig udfører indlejrede EarlyPhases opkald.

Branch D Parallel Tasks Start

Dette er det tredje trin i udførelsessekvensen:

  1. Afdeling A (overordnet opgave).
  2. Afdeling C (yderligere parallelle opgaver).
  3. Afdeling D (yderligere parallelle opgaver).
  4. Afdeling B (yderligere parallelle opgaver).

Frigivet fra sin CXPACKET vent på forbrugersiden af ​​ompartitionsstrømudvekslingen ved node 5, overordnet opgave stiger op gren B-forespørgselsscanningstræet. Det vender tilbage fra indlejrede EarlyPhases opkald til de forskellige iteratorer og profiler på den ydre (øvre) input af flette-sammenføjningen.

Som nævnt stigende træet opdaterer de forløbne og CPU-tider, der er registreret af de usynlige profilerings-iteratorer. Vi udfører kode ved hjælp af den overordnede opgave, så disse tal registreres mod udførelseskontekst nul. Dette er den ultimative kilde til "tråd 0"-timingnumrene, der henvises til i min tidligere artikel, Understanding Execution Plan Operator Timings.

Når du er tilbage ved sammenfletningen, kalder den overordnede opgave EarlyPhases for iteratorerne og profilerne på det indre (nedre) input til flettesammenføjningen. Disse er noder 10 til 15 (ekskl. 14, som er udskudt):

Når den overordnede opgaves tidlige fasekald når indekssøgningen ved node 15, begynder den at stige op i træet igen (indstille profileringstider), indtil den når ompartitionsstrømudvekslingen ved node 11.

Derefter, ligesom det gjorde på det ydre (øverste) input til flettesammenføjningen, starter den producentsiden af centralen ved node 11 , oprettelse af to nye parallelle opgaver .
Dette sætter gren D i gang (vist nedenfor). Gren D udfører nøjagtigt som allerede beskrevet i detaljer for gren C.

Umiddelbart efter start af opgaver for gren D, venter overordnet opgaveCXPACKET ved node 11 for at de nye producenter kan åbne udvekslingsporten:

Den nye CXPACKET ventetider er fremhævet. Bemærk, at det rapporterede node-id kan være en smule misvisende. Den overordnede opgave venter i virkeligheden på forbrugersiden af ​​node 11 (opdelingsstrømme), ikke node 2 (saml strømme). Dette er et særpræg ved behandling i den tidlige fase.

I mellemtiden fortsætter producenttrådene i Branch C med at vente på CXPACKET for forbrugersiden af ​​noden 5 udveksles opdelingsstrømme for at åbne.

Afdeling D åbning

Lige efter den overordnede opgave starter producenterne for gren D, forespørgselsprofilen DMV viser de nye udførelseskontekster (3 og 4):

De to nye parallelle opgaver i gren D fortsætter nøjagtigt som dem i gren C gjorde. Sorteringerne optager alle deres input, og Branch D-opgaverne vender tilbage til centralen. Dette frigiver den overordnede opgave fra dens CXPACKET vente. Branch D-arbejderne venter derefter på CXPACKET på producentsiden af ​​node 11 for at åbne parallelle opgaver på forbrugersiden. Disse parallelarbejdere (i gren B) eksisterer ikke endnu.

Checkpoint

De ventende opgaver på dette tidspunkt er vist nedenfor:

Begge sæt parallelle opgaver i grenene C og D venter på CXPACKET for at deres parallelle opgave forbrugere skal åbne, ved opdelingsstrømme udveksler noderne 5 og 11 hhv. Den eneste kørebare opgave i hele forespørgslen lige nu er overordnet opgave .

Forespørgselsprofiler DMV på dette tidspunkt er vist nedenfor, med operatører i grenene C og D fremhævet:

De eneste parallelle opgaver, vi endnu ikke har startet, er i afdeling B. Alt arbejdet i afdeling B har indtil videre været tidlige faser opkald udført af overordnet opgave .

Slut på del 4

I den sidste del af denne serie vil jeg beskrive, hvordan resten af ​​denne særlige parallelle eksekveringsplan starter op, og kort dække, hvordan planen giver resultater. Jeg vil afslutte med en mere generel beskrivelse, der gælder for parallelle planer af vilkårlig kompleksitet.


  1. Sådan fungerer FORMAT() i MariaDB

  2. STRING_SPLIT() i SQL Server 2016:Opfølgning #1

  3. PostgreSQL-funktion til sidst indsatte ID

  4. Skjulte funktioner i PostgreSQL