Ini adalah bagian keempat dari seri lima bagian yang membahas secara mendalam cara rencana paralel mode baris SQL Server mulai dijalankan. Bagian 1 menginisialisasi konteks eksekusi nol untuk tugas induk, dan bagian 2 membuat pohon pemindaian kueri. Bagian 3 memulai pemindaian kueri, melakukan beberapa fase awal pemrosesan, dan memulai tugas paralel tambahan pertama di cabang C.
Detail eksekusi Cabang C
Ini adalah langkah kedua dari urutan eksekusi:
- Cabang A (tugas induk).
- Cabang C (tugas paralel tambahan).
- Cabang D (tugas paralel tambahan).
- Cabang B (tugas paralel tambahan).
Pengingat akan cabang-cabang dalam paket paralel kami (klik untuk memperbesar)
Beberapa saat setelah tugas baru untuk cabang C diantrekan, SQL Server melampirkan pekerja untuk setiap tugas, dan menempatkan pekerja di penjadwal siap untuk dieksekusi. Setiap tugas baru berjalan di dalam konteks eksekusi baru. Di DOP 2, ada dua tugas baru, dua utas pekerja, dan dua konteks eksekusi untuk cabang C. Setiap tugas menjalankan salinan iteratornya sendiri di cabang C pada utas pekerjanya sendiri:
Dua tugas paralel baru mulai berjalan pada sub-prosedur titik masuk, yang awalnya mengarah ke Open
hubungi pihak produsen bursa (CQScanXProducerNew::Open
). Kedua tugas memiliki tumpukan panggilan yang identik di awal kehidupannya:
Sinkronisasi pertukaran
Sementara itu, tugas induk (berjalan pada utas pekerjanya sendiri) mendaftarkan sub-proses baru dengan manajer sub-proses, lalu menunggu di sisi konsumen dari pertukaran aliran partisi ulang pada node 5. Tugas induk menunggu di CXPACKET
* sampai semua tugas paralel cabang C menyelesaikan Open
panggilan dan kembali ke sisi produsen pertukaran. Tugas paralel akan membuka setiap iterator di subpohonnya (yaitu hingga pencarian indeks pada node 9 dan kembali) sebelum kembali ke pertukaran aliran partisi ulang pada node 5. Tugas induk akan menunggu di CXPACKET
sementara ini terjadi. Ingat tugas orang tua adalah menjalankan panggilan fase awal.
Kita dapat melihat penantian ini dalam tugas menunggu DMV:
Eksekusi konteks nol (tugas induk) diblokir oleh kedua konteks eksekusi baru. Konteks eksekusi . ini adalah tambahan pertama yang dibuat setelah konteks nol, jadi mereka diberi nomor satu dan dua. Untuk menekankan:Kedua konteks eksekusi baru perlu membuka subpohonnya dan kembali ke pertukaran untuk CXPACKET
tugas induk tunggu sampai selesai.
Anda mungkin mengharapkan untuk melihat CXCONSUMER
menunggu di sini, tetapi menunggu itu dicadangkan untuk menunggu di data baris untuk tiba. Penantian saat ini bukan untuk baris — itu untuk pihak produsen untuk membuka , jadi kami mendapatkan CXPACKET
generik * tunggu.
* Database Azure SQL dan Instans Terkelola menggunakan CXSYNC_PORT
baru tunggu alih-alih CXPACKET
di sini, tetapi peningkatan itu belum masuk ke SQL Server (per 2019 CU9).
Memeriksa tugas paralel baru
Kita dapat melihat tugas baru di profil kueri DMV. Informasi profil untuk tugas baru muncul di DMV karena konteks eksekusinya diturunkan (dikloning, lalu diperbarui) dari induknya (konteks eksekusi nol):
Sekarang ada tiga entri untuk setiap iterator di Cabang C (disorot). Satu untuk tugas induk (konteks eksekusi nol), dan satu untuk setiap tugas paralel tambahan baru (konteks 1 dan 2). Perhatikan bahwa perkiraan jumlah baris per-utas ( lihat bagian 1) telah tiba sekarang, dan ditampilkan hanya untuk tugas paralel. Waktu aktif pertama dan terakhir untuk tugas paralel mewakili waktu konteks eksekusi mereka dibuat. Tidak ada tugas baru yang dibuka belum ada iterator.
Aliran partisi ulang pertukaran pada node 5 masih hanya memiliki satu entri dalam output DMV. Ini karena profiler tak terlihat yang terkait memantau konsumen sisi pertukaran. Tugas paralel tambahan ada di produser sisi pertukaran. Sisi konsumen dari simpul 5 akan akhirnya memiliki tugas paralel, tetapi kami belum mencapai titik itu.
Pos pemeriksaan
Ini sepertinya poin yang bagus untuk berhenti sejenak dan meringkas di mana semuanya berada saat ini. Akan ada lebih banyak titik pemberhentian ini seiring berjalannya waktu.
- Tugas orang tua ada di sisi konsumen pertukaran aliran partisi ulang di node 5 , menunggu di
CXPACKET
. Itu sedang dalam pelaksanaan panggilan fase awal. Itu berhenti untuk memulai Cabang C karena cabang itu berisi semacam pemblokiran. Penantian tugas induk akan berlanjut hingga kedua tugas paralel selesai membuka subpohonnya. - Dua tugas paralel baru di sisi produsen pertukaran node 5 siap untuk membuka iterator di Cabang C.
Tidak ada di luar Cabang C dari rencana eksekusi paralel ini yang dapat membuat kemajuan sampai tugas induk dilepaskan dari CXPACKET
tunggu. Ingat kita hanya membuat satu set pekerja paralel tambahan sejauh ini, untuk Cabang C. Satu-satunya utas lainnya adalah tugas induk, dan itu diblokir.
Eksekusi Paralel Cabang C
Dua tugas paralel dimulai dari sisi produsen dari pertukaran aliran partisi ulang pada simpul 5. Masing-masing memiliki rencana (serial) terpisah dengan agregat aliran, pengurutan, dan pencarian indeksnya sendiri. Skalar komputasi tidak muncul dalam rencana waktu proses karena penghitungannya ditangguhkan ke pengurutan.
Setiap instance pencarian indeks sadar paralel dan beroperasi pada set baris yang terputus-putus. Set ini dihasilkan sesuai permintaan dari rowset induk yang dibuat sebelumnya oleh tugas induk (dibahas di bagian 1). Ketika salah satu instance dari pencarian membutuhkan subrentang baru dari baris, itu akan disinkronkan dengan utas pekerja lainnya, sehingga hanya satu yang mengalokasikan subrentang baru pada saat yang sama. Objek sinkronisasi yang digunakan juga dibuat sebelumnya oleh tugas induk. Saat tugas menunggu akses eksklusif ke rowset induk untuk memperoleh subrentang baru, tugas menunggu di CXROWSET_SYNC
.
Tugas Cabang C terbuka
Urutan Open
panggilan untuk setiap tugas di Cabang C adalah:
CQScanXProducerNew::Open
. Perhatikan bahwa tidak ada profiler sebelumnya di sisi produsen bursa. Ini sangat disayangkan untuk penyetel kueri.CXTransLocal::Open
CXPort::Register
CXTransLocal::ActivateWorkers
CQScanProfileNew::Open
. Profiler di atas simpul 6.CQScanStreamAggregateNew::Open
(simpul 6)CQScanProfileNew::Open
. Profiler di atas simpul 7.CQScanSortNew::Open
(simpul 7)
Sortir adalah operator pemblokiran fully . Ia menghabiskan seluruh inputnya selama Open
panggilan. Ada banyak sekali detail internal yang menarik untuk dijelajahi di sini, tetapi ruangnya terbatas, jadi saya hanya akan membahas hal-hal penting:
mengurutkan membangun tabel pengurutannya dengan membuka subpohonnya dan menggunakan semua baris yang dapat disediakan oleh turunannya. Setelah penyortiran selesai, pengurutan siap untuk transisi ke mode output, dan mengembalikan kontrol ke induknya. Pengurutan ini nantinya akan merespons GetRow()
panggilan, mengembalikan baris yang diurutkan berikutnya setiap kali. Tumpukan panggilan ilustratif selama input pengurutan adalah:
Eksekusi berlanjut hingga setiap jenis menghabiskan semua (rentang terputus-putus) baris yang tersedia dari pencarian indeks turunannya . Sortir kemudian memanggil Close
pada pencarian indeks, dan mengembalikan kontrol ke agregat aliran induknya . Agregat aliran menginisialisasi penghitungnya dan mengembalikan kontrol ke produser sisi pertukaran partisi ulang pada node 5. Urutan Open
panggilan sekarang selesai di cabang ini.
DMV pembuatan profil pada titik ini menunjukkan nomor waktu yang diperbarui, dan waktu tutup untuk pencarian indeks paralel:
Sinkronisasi pertukaran lainnya
Ingat tugas induk sedang menunggu di konsumen sisi node 5 untuk semua produsen untuk membuka. Proses sinkronisasi serupa sekarang terjadi di antara tugas paralel di produser sisi pertukaran yang sama:
Setiap tugas produser disinkronkan dengan yang lain melalui CXTransLocal::Synchronize
. Produsen memanggil CXPort::Open
, lalu tunggu di CXPACKET
untuk semua sisi konsumen tugas paralel untuk dibuka. Ketika tugas paralel Cabang C pertama tiba kembali di sisi produsen bursa dan menunggu, tugas menunggu DMV terlihat seperti ini:
Kami masih memiliki sisi konsumen tugas orang tua menunggu. CXPACKET
baru disorot adalah tugas paralel sisi produsen pertama kami yang menunggu semua tugas paralel sisi konsumen untuk membuka port pertukaran.
Tugas paralel sisi konsumen (di Cabang B) bahkan belum ada, jadi tugas produser menampilkan NULL untuk konteks eksekusi yang diblokirnya. Tugas yang saat ini menunggu di sisi konsumen dari pertukaran aliran partisi ulang adalah tugas induk (bukan tugas paralel!) yang menjalankan EarlyPhases
kode, jadi tidak dihitung.
Tugas induk CXPACKET menunggu berakhir
Saat kedua tugas paralel di Cabang C tiba kembali di sisi produsen pertukaran dari Open
panggilan, semua produsen telah membuka port pertukaran, jadi tugas induk di sisi konsumen pertukaran dirilis dari CXPACKET
tunggu.
Para pekerja di sisi produsen terus menunggu tugas paralel sisi konsumen dibuat dan membuka port pertukaran:
Pos pemeriksaan
Saat ini:
- Total ada tiga tugas:Dua di Cabang C, ditambah tugas induk.
- Keduanya produser di simpul 5 pertukaran telah dibuka, dan menunggu di
CXPACKET
untuk membuka tugas paralel sisi konsumen. Sebagian besar mesin pertukaran (termasuk buffer baris) dibuat oleh sisi konsumen, jadi belum ada tempat bagi produsen untuk meletakkan baris. - Yang mengurutkan di Cabang C telah menggunakan semua inputnya, dan siap memberikan output yang diurutkan.
- Indeks mencari di Cabang C telah menyelesaikan pekerjaannya dan ditutup.
- Tugas orang tua baru saja dibebaskan dari menunggu
CXPACKET
di sisi konsumen node 5 partisi ulang aliran pertukaran. Itu masih mengeksekusiEarlyPhases
panggilan.
Tugas Paralel Cabang D Dimulai
Ini adalah langkah ketiga dalam urutan eksekusi:
- Cabang A (tugas induk).
- Cabang C (tugas paralel tambahan).
- Cabang D (tugas paralel tambahan).
- Cabang B (tugas paralel tambahan).
Dirilis dari CXPACKET
tunggu di sisi konsumen dari pertukaran aliran partisi ulang di node 5, tugas induk naik pohon pemindaian kueri Cabang B. Ini kembali dari EarlyPhases
bersarang panggilan ke berbagai iterator dan profiler di input luar (atas) dari gabungan gabungan.
Seperti yang disebutkan, naik pohon memperbarui waktu yang telah berlalu dan waktu CPU yang direkam oleh iterator pembuatan profil yang tidak terlihat. Kami mengeksekusi kode menggunakan tugas induk, sehingga angka-angka tersebut dicatat dengan konteks eksekusi nol. Ini adalah sumber utama dari nomor waktu "utas 0" yang dirujuk dalam artikel saya sebelumnya, Memahami Waktu Operator Rencana Eksekusi.
Setelah kembali bergabung, tugas induk memanggil EarlyPhases
untuk iterator dan profiler pada input bagian dalam (bawah) ke gabungan gabungan. Ini adalah simpul 10 hingga 15 (tidak termasuk 14, yang ditangguhkan):
Setelah panggilan fase awal tugas induk mencapai pencarian indeks di node 15, itu mulai naik pohon lagi (mengatur waktu pembuatan profil) hingga mencapai pertukaran aliran partisi ulang di node 11.
Kemudian, seperti yang terjadi pada input luar (atas) ke gabungan gabungan, memulai sisi produsen pertukaran di simpul 11 , membuat dua tugas paralel baru .
Ini membuat Cabang D bergerak (ditunjukkan di bawah). Cabang D mengeksekusi persis seperti yang telah dijelaskan secara rinci untuk Cabang C.
Segera setelah memulai tugas untuk Cabang D, tugas induk menunggu di CXPACKET
di node 11 untuk produsen baru untuk membuka port pertukaran:
CXPACKET
baru menunggu disorot. Perhatikan id simpul yang dilaporkan mungkin sedikit menyesatkan. Tugas induk benar-benar menunggu di sisi konsumen dari simpul 11 (aliran partisi ulang), bukan simpul 2 (pengumpulan arus). Ini adalah kekhasan dari pemrosesan fase awal.
Sementara itu, utas produsen di Cabang C terus menunggu di CXPACKET
untuk sisi konsumen dari node 5 pertukaran aliran partisi ulang untuk membuka.
Pembukaan Cabang D
Tepat setelah tugas induk memulai produser untuk Cabang D, profil kueri DMV menunjukkan konteks eksekusi baru (3 dan 4):
Dua tugas paralel baru di Cabang D berjalan persis seperti yang dilakukan di Cabang C. Jenis mengkonsumsi semua input mereka, dan tugas Cabang D kembali ke bursa. Ini melepaskan tugas induk dari CXPACKET
its tunggu. Pekerja Cabang D kemudian menunggu CXPACKET
di sisi produsen simpul 11 untuk tugas paralel sisi konsumen untuk dibuka. Pekerja paralel itu (di Cabang B) belum ada.
Pos pemeriksaan
Tugas menunggu pada titik ini ditunjukkan di bawah ini:
Kedua set tugas paralel di Cabang C dan D sedang menunggu di CXPACKET
untuk dibuka oleh konsumen tugas paralel mereka, pada aliran partisi ulang, masing-masing bertukar node 5 dan 11. Satu-satunya tugas yang dapat dijalankan di seluruh kueri sekarang adalah tugas induk .
Profiler kueri DMV pada titik ini ditunjukkan di bawah, dengan operator di Cabang C dan D disorot:
Satu-satunya tugas paralel yang belum kami mulai adalah di Cabang B. Semua pekerjaan di Cabang B sejauh ini tahap awal panggilan yang dilakukan oleh tugas induk .
Akhir Bagian 4
Di bagian akhir dari seri ini, saya akan menjelaskan bagaimana sisa dari rencana eksekusi paralel khusus ini dimulai, dan secara singkat membahas bagaimana rencana tersebut mengembalikan hasil. Saya akan menyimpulkan dengan deskripsi yang lebih umum yang berlaku untuk rencana paralel dengan kompleksitas arbitrer.