Това е четвъртата част от поредица от пет части, която прави дълбоко потапяне в начина, по който започват да се изпълняват паралелните планове в режим на ред на SQL Server. Част 1 инициализира нулев контекст на изпълнение за родителската задача, а част 2 създаде дървото за сканиране на заявка. Част 3 стартира сканирането на заявката, изпълни някаква ранна фаза обработка и стартира първите допълнителни паралелни задачи в клон C.
Подробности за изпълнение на клон C
Това е втората стъпка от последователността на изпълнение:
- Клон А (родителска задача).
- Клон C (допълнителни паралелни задачи).
- Клон D (допълнителни паралелни задачи).
- Клон Б (допълнителни паралелни задачи).
Напомняне за клоновете в нашия паралелен план (щракнете за уголемяване)
Малко време след новите задачи за клон C са поставени на опашка, SQL Server прикачва работник към всяка задача и поставя работника в планировчик готов за изпълнение. Всяка нова задача се изпълнява в нов контекст на изпълнение. В DOP 2 има две нови задачи, две работни нишки и два контекста на изпълнение за клон C. Всяка задача изпълнява свое собствено копие на итераторите в клон C на собствената си работна нишка:
Двете нови паралелни задачи започват да се изпълняват в подпроцедура входна точка, която първоначално води до Open
извикване от страна на производителя на борсата (CQScanXProducerNew::Open
). И двете задачи имат идентични стекове от обаждания в началото на живота си:
Синхронизиране на обмен
Междувременно родителската задача (работи на собствена работна нишка) регистрира новите подпроцеси в мениджъра на подпроцеси, след което изчаква от страна на потребитела на обмен на потоци за преразпределение на възел 5. Родителската задача изчаква на CXPACKET
* довсички на паралелните задачи на клон C завършват своя Open
обаждания и връщане към страната на производителя на борсата. Паралелните задачи ще отворят всеки итератор в тяхното поддърво (т.е. до търсене на индекса на възел 9 и обратно), преди да се върне към обмена на потоци за преразпределение на възел 5. Родителската задача ще изчака на CXPACKET
докато това се случва. Не забравяйте, че родителската задача изпълнява обаждания в ранните фази.
Можем да видим това чакане в чакащите задачи DMV:
Нулевият контекст на изпълнение (родителската задача) е блокиран от двата нови контекста на изпълнение. Тези контексти на изпълнение са първите допълнителни, които се създават след нулев контекст, така че им се приписват номера едно и две. За да подчертаем:И двата нови контекста на изпълнение трябва да отворят своите поддървета и да се върнат към обмена за CXPACKET
на родителската задача изчакайте края.
Може да сте очаквали да видите CXCONSUMER
чака тук, но това изчакване е запазено за изчакване на данни в ред пристигам. Текущото изчакване не е за редове — от страна на производителя е да отваря , така че получаваме общ CXPACKET
* изчакайте.
* Azure SQL база данни и управляван екземпляр използват новия CXSYNC_PORT
изчакайте вместо CXPACKET
тук, но това подобрение все още не е проникнало в SQL Server (от 2019 CU9).
Проверка на новите паралелни задачи
Можем да видим новите задачи в профилите на заявка DMV. Информацията за профилиране за новите задачи се появява в DMV, тъй като техните контексти на изпълнение са получени (клонирани, след това актуализирани) от родителския (нулев контекст на изпълнение):
Вече има три записа за всеки итератор в клон C (маркиран). Един за родителската задача (нулев контекст на изпълнение) и един за всяка нова допълнителна паралелна задача (контексти 1 и 2). Обърнете внимание, че броят на прогнозния ред за нишка (вижте част 1) са пристигнали сега и са показани само за паралелните задачи. Първото и последното активно време тъй като паралелните задачи представляват времето, когато са създадени техните контексти за изпълнение. Нито една от новите задачи не е отворена все още няма итератори.
Потоците за повторно разделяне обменът на възел 5 все още има само един запис в изхода на DMV. Това е така, защото свързаният невидим профайлър следи потребителя страна на борсата. Допълнителните паралелни задачи са на производителя страна на борсата. Потребителската страна на възел 5 ще в крайна сметка имат паралелни задачи, но все още не сме стигнали до тази точка.
Контролен пункт
Това изглежда като добра точка да спрете за дъх и да обобщите къде е всичко в момента. Ще има повече от тези точки на спиране, докато вървим напред.
- Родителската задача е на потребителската страна на обменните потоци за преразпределение в възел 5 , чака на
CXPACKET
. Той е в средата на изпълнение на обажданията в ранните фази. Той спря, за да стартира клон C, защото този клон съдържа блокиращо сортиране. Изчакването на родителската задача ще продължи, докато и двете паралелни задачи не завършат отварянето на своите поддървета. - Две нови паралелни задачи отстрана на производителя на обменния възел 5 са готови за отваряне на итераторите в клон C.
Нищо извън клон C на този план за паралелно изпълнение не може да напредва напред, докато родителската задача не бъде освободена от нейния CXPACKET
изчакайте. Не забравяйте, че досега сме създали само един набор от допълнителни паралелни работници за клон C. Единствената друга нишка е родителската задача и тя е блокирана.
Паралелно изпълнение на клон C
Двете паралелни задачи започват отстрана на производителя на обменните потоци за преразпределение на възел 5. Всеки има отделен (сериен) план със свой собствен агрегат за поток, сортиране и търсене на индекс. Изчислителният скалар не се появява в плана по време на изпълнение, тъй като изчисленията му се отлагат за сортирането.
Всеки екземпляр на търсенето на индекс е паралелно наясно и оперира с несвързани набори от редове. Тези набори се генерират при поискване от родителския набор от редове, създаден по-рано от родителската задача (обхванати в част 1). Когато който и да е екземпляр на търсенето се нуждае от нов поддиапазон от редове, той се синхронизира с другите работни нишки, така че само един от тях разпределя нов поддиапазон по едно и също време. Използваният обект за синхронизация също е създаден по-рано от родителската задача. Когато задача чака изключителен достъп до родителския набор от редове, за да придобие нов поддиапазон, тя изчаква на CXROWSET_SYNC
.
Отворени задачи на клон C
Последователността на Open
повикванията за всяка задача в клон C е:
CQScanXProducerNew::Open
. Забележете, че няма предходен профайлър от страна на производителя на борсата. Това е жалко за тунерите на заявки.CXTransLocal::Open
CXPort::Register
CXTransLocal::ActivateWorkers
CQScanProfileNew::Open
. Профилизаторът над възел 6.CQScanStreamAggregateNew::Open
(възел 6)CQScanProfileNew::Open
. Профилизаторът над възел 7.CQScanSortNew::Open
(възел 7)
Сортирането е напълно блокиращ оператор . Той консумира целия си вход по време на своя Open
обадете се. Тук има голям брой интересни вътрешни детайли за изследване, но пространството е малко, така че ще покрия само акцентите:
Сортита изгражда своята таблица за сортиране, като отваря своето поддърво и консумира всички редове, които децата му могат да предоставят. След като сортирането приключи, сортирането е готово да премине към изходен режим и връща контрола на своя родител. Сортирането по-късно ще отговори на GetRow()
извиквания, връщайки всеки път следващия сортиран ред. Илюстративен стек от повиквания по време на въвеждане на сортиране е:
Изпълнението продължава, докато всяко сортиране не погълне всички (отделени диапазони от) редове, налични от неговото дъщерно търсене на индекс . След това сортирането извиква Close
на търсене на индекса и връщат контрола на родителския им агрегат на потока . Агрегатите на потока инициализират своите броячи и връщат контрола на производителя страна на обмена на преразпределение в възел 5. Последователността на Open
повикванията вече са завършени в този клон.
Профилиращият DMV в този момент показва актуализирани номера на времето и часа на затваряне за паралелния индекс търси:
Още синхронизиране на обмен
Припомнете си, че родителската задача чака на потребителя страна на възел 5 за отваряне на всички производители. Подобен процес на синхронизиране вече се случва сред паралелните задачи на производителя страна на същия обмен:
Всяка задача на производителя се синхронизира с другите чрез CXTransLocal::Synchronize
. Производителите извикват CXPort::Open
, след което изчакайте CXPACKET
за всички потребители паралелни задачи за отваряне. Когато първата паралелна задача на клон C пристигне обратно от страната на производителя на борсата и изчака, изчакващите задачи DMV изглеждат така:
Все още имаме изчаквания от страна на потребителя на родителската задача. Новият CXPACKET
подчертано е първата ни паралелна задача от страна на производителя, която чака за всички паралелни задачи от страна на потребителите за да отворите порта за обмен.
Паралелните задачи от страна на потребителя (в клон B) дори не съществуват, така че задачата на производителя показва NULL за контекста на изпълнение, от който е блокирана. Задачата, която в момента чака от страна на потребителя на обмена на потоци за преразпределение, е родителската задача (не паралелна задача!), изпълняваща EarlyPhases
код, така че не се брои.
Родителската задача CXPACKET чака край
Когато вторият паралелната задача в клон C пристига обратно на страната на производителя на борсата от нейния Open
повиквания, всички производители са отворили порта за обмен, така че родителската задача от страна на потребитела на борсата еосвободен от неговия CXPACKET
изчакай.
Работниците от страна на производителя продължават да чакат да бъдат създадени паралелни задачи от страна на потребителя и да отворят порта за обмен:
Контролен пункт
В този момент:
- Има общо три задачи:Две в клон C плюс задачата родител.
- И двамата продуценти на възел 5 борсата са отворени и чакат на
CXPACKET
за отваряне на паралелни задачи от страна на потребителя. Голяма част от механизмите за обмен (включително буферите за редове) се създават от страна на потребителите, така че производителите все още няма къде да поставят редове. - Сортовете в клон C са изразходвали целия си вход и са готови да предоставят сортиран изход.
- Индексът търси в клон C са приключили работата си и са затворени.
- Родителската задача току-що беше освободен от чакане на
CXPACKET
от страната на потребителя на възела 5 се обменят потоци за преразпределение. Все още е изпълнение на вложениEarlyPhases
обаждания.
Старт на паралелни задачи на клон D
Това е третата стъпка в последователността на изпълнение:
- Клон А (родителска задача).
- Клон C (допълнителни паралелни задачи).
- Клон D (допълнителни паралелни задачи).
- Клон Б (допълнителни паралелни задачи).
Освободен от неговия CXPACKET
изчакайте от страната на потребителя на обмена на потоци за преразпределение на възел 5, родителската задача изкачва се дървото за сканиране на заявка за клон B. Връща се от вложени EarlyPhases
извиквания към различните итератори и профайлери на външния (горния) вход на обединението за сливане.
Както бе споменато, възходящ дървото актуализира изминалото и процесорното време, записани от невидимите профилиращи итератори. Ние изпълняваме код, използвайки родителската задача, така че тези числа се записват срещу нулев контекст на изпълнение. Това е най-големият източник на времевите числа на „нишка 0“, споменати в предишната ми статия, Разбиране на времената на оператора на план за изпълнение.
След като се върне при присъединяването към сливането, родителската задача извиква EarlyPhases
за итераторите и профайлърите на вътрешния (долния) вход към обединението за сливане. Това са възли от 10 до 15 (с изключение на 14, което е отложено):
След като извикванията на ранните фази на родителската задача достигнат търсенето на индекс на възел 15, тя започва да се изкачва отново по дървото (задаване на времена за профилиране), докато достигне обмена на потоци за преразпределение на възел 11.
След това, точно както направи на външния (горния) вход на обединението за сливане, започва страната на производителя на борсата ввъзел 11 , създавайкидве нови паралелни задачи .
Това привежда клон D в движение (показан по-долу). Клон D се изпълнява точно както вече е описано подробно за клон C.
Веднага след стартиране на задачи за клон D, родителската задача изчаква на CXPACKET
на възел 11 за новите производители да отворят порта за обмен:
Новият CXPACKET
изчакванията са подчертани. Обърнете внимание, че отчетеният идентификатор на възел може да е малко подвеждащ. Родителската задача наистина чака от страната на потребителя на възел 11 (потоци за повторно разделяне), а не на възел 2 (събиране на потоци). Това е странност на обработката в ранна фаза.
Междувременно нишките на производителите в клон C продължават да чакат на CXPACKET
за потребителската страна на възела 5 потоци за преразпределение се обменят, за да се отворят.
Отваряне на клон D
Точно след като родителската задача стартира производителите за клон D, профилът на заявката DMV показва новите контексти на изпълнение (3 и 4):
Двете нови паралелни задачи в клон D действат точно както тези в клон C. Сортовете консумират целия им вход и задачите на клон D се връщат в обмена. Това освобождава родителската задача от нейния CXPACKET
изчакайте. След това работниците от клон D изчакват CXPACKET
от страната на производителя на възел 11 за отваряне на паралелни задачи от страна на потребителя. Тези паралелни работници (в клон Б) все още не съществуват.
Контролен пункт
Изчакващите задачи в този момент са показани по-долу:
И двата набора паралелни задачи в клонове C и D чакат на CXPACKET
за тяхната паралелна задача потребителите да отворят, при преразпределение потоци обменят възли съответно 5 и 11. Единствената задача, която може да се изпълнява в цялата заявка в момента е родителската задача .
DMV за профилиране на заявки в този момент е показан по-долу, като операторите в клонове C и D са подчертани:
Единствените паралелни задачи, които все още не сме започнали, са в клон B. Цялата работа в клон B досега беше ранни фази повиквания, извършвани от родителската задача .
Край на част 4
В последната част на тази серия ще опиша как започва остатъкът от този конкретен план за паралелно изпълнение и накратко ще обясня как планът връща резултати. Ще завърша с по-общо описание, което се отнася за паралелни планове с произволна сложност.