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:
- Afdeling A (overordnet opgave).
- Gren C (yderligere parallelle opgaver).
- Afdeling D (yderligere parallelle opgaver).
- 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 venter på forbrugersiden 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 opgaver på producentsiden 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ælderopgaven på forbrugersiden 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 venter på
CXPACKET
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 indlejredeEarlyPhases
opkald.
Branch D Parallel Tasks Start
Dette er det tredje trin i udførelsessekvensen:
- Afdeling A (overordnet opgave).
- Afdeling C (yderligere parallelle opgaver).
- Afdeling D (yderligere parallelle opgaver).
- 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 opgave på CXPACKET
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.