Petunjuk tablock memicu kebuntuan

10

Saya menyisipkan dua set data, menggunakan penebangan minimal, ke tabel tumpukan kosong menggunakan melalui dua Jalankan Tugas SQL yang berjalan secara paralel dan dengan SQL dari formulir berikut.

INSERT INTO Table (TABLOCK) SELECT FROM ...

Setelah pekerjaan sedikit hang, salah satu tugas SQL menjadi korban kebuntuan. Di bawah ini adalah output XML dari grafik deadlock.

Dapatkah seseorang menjelaskan apa yang terjadi di bawah tenda?

  <resource-list>
   <objectlock lockPartition="0" objid="1586156746" subresource="FULL" dbid="7" objectname="dbo.TargetTable" id="lock7374a00" mode="IX" associatedObjectId="1586156746">
    <owner-list>
     <owner id="process9609dc8" mode="Sch-S"/>
     <owner id="process9609dc8" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process5e13048" mode="X" requestType="convert"/>
    </waiter-list>
   </objectlock>
   <objectlock lockPartition="0" objid="1586156746" subresource="FULL" dbid="7" objectname="dbo.TargetTable" id="lock7374a00" mode="IX" associatedObjectId="1586156746">
    <owner-list>
     <owner id="process5e13048" mode="Sch-S"/>
     <owner id="process5e13048" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process9609dc8" mode="X" requestType="convert"/>
    </waiter-list>
   </objectlock>
  </resource-list>

Banyak hal menjadi lebih rumit karena saya menemukan bahwa untuk sebagian besar kasus, kedua Execute SQL Tasks dapat berjalan secara paralel dengan sukses. Coba di bawah ini:

Create table dbo.TablockInsert (c1 int, c2 int, c3 int)

--then issue the script in two Execute Sql Task in parallel you won't fail:
insert into dbo.TablockInsert(TABLOCK) SELECT 1, 1, 1

Karena satu-satunya perbedaan adalah pernyataan SELECT ... FROM ..., sepertinya pernyataan SELECT ... FROM ... dapat berdampak pada mode kunci di sini?

SqlWhale
sumber
Anda bisa menentukan TABLOCKX alih-alih TABLOCK untuk mencegah kebuntuan. Meskipun itu juga akan membuat serial akses ke tabel, Anda masih akan mendapatkan logging minimal.
Dan Guzman

Jawaban:

8

The data Memuat Panduan Kinerja ditulis untuk SQL Server 2008 tetapi sejauh yang saya tahu Microsoft belum membuat perbaikan di daerah ini untuk tumpukan. Berikut kutipan untuk skenario pemuatan Anda:

Memuat Massal Tabel Kosong, Tidak Berpartisi

Memuat data ke tabel non-partisi, sementara operasi sederhana, dapat dioptimalkan dengan beberapa cara.

...

Beberapa, operasi penyisipan bersamaan untuk tumpukan dimungkinkan hanya ketika metode massal yang dipilih mengeluarkan pembaruan massal (BU) mengunci pada tabel. Dua kunci pembaruan massal (BU) kompatibel, dan karenanya dua operasi massal dapat berjalan secara bersamaan.

Dalam skenario ini, baik INSERT ... SELECT dan SELECT INTO memiliki kekurangan. Kedua operasi ini mengambil kunci level tabel eksklusif (X) pada tujuan. Ini berarti bahwa hanya satu operasi muatan curah yang dapat berjalan pada waktu tertentu, sehingga membatasi skalabilitas. Namun, BCP, BULK INSERT, dan Layanan Integrasi semua mampu mengambil kunci pembaruan massal (BU) - jika Anda menentukan petunjuk TABLOCK.

Bagian penting adalah Anda tidak mendapatkan kunci BU INSERT ... SELECT. Anda akan selalu mendapatkan kunci eksklusif di atas meja, sehingga hanya satu yang INSERTdapat berjalan sekaligus.

Dalam komentar yang Anda katakan bahwa Anda akan menyisipkan baris 100rb atau kurang dan bahwa proses lain tidak akan berjalan di tabel selama sisipan. Saat mengirim dua pertanyaan INSERT ke database, saya berharap satu dari tiga hal terjadi:

  1. Satu insert berjalan terlebih dahulu dan memblokir insert lainnya. Sisipan kedua menunggu sampai penyisipan pertama selesai.
  2. Satu insert selesai sebelum insert kedua dimulai. Tidak ada pemblokiran eksplisit tetapi mereka tidak berjalan secara bersamaan.
  3. Anda mendapatkan jalan buntu dan hanya satu sisipan berhasil diselesaikan.

Dalam semua kasus, Anda mendapat manfaat atau tidak terluka dengan menambahkan TABLOCKXpetunjuk ke kueri, jadi itu adalah rekomendasi saya untuk mengatasi kebuntuan. Jika Anda ingin tahu mengapa kebuntuan kadang terjadi, Anda perlu mencari jawaban lain untuk itu.

Karena dalam skenario yang berbeda di mana Anda benar-benar membutuhkan penyisipan paralel, dua cara untuk mengatasi masalah BU adalah mempartisi tumpukan Anda dan menyuruh setiap sesi menyisipkan ke dalam partisi terpisah atau memuat data Anda melalui BCP, BULK INSERT, atau Layanan Integrasi .

Joe Obbish
sumber
Terima kasih atas jawabannya, tetapi situasi yang saya hadapi menemui jalan buntu adalah satu-satunya kasus yang saya miliki sekarang. Untuk sebagian besar kasus ketika Anda mengeluarkan INSERT INTO WITH (TABLOCK) SELECT FROM secara paralel, pekerjaan tidak akan gagal. BTW, saya menggunakan SQL SERVER 2008 R2. Saya telah menambahkan contoh sukses dalam pertanyaan saya.
SqlWhale
@ TEC dalam kasus itu tidak gagal mungkin mereka benar-benar berakhir berjalan seri. Mungkin Anda hanya mendapatkan masalah ketika ada waktu start up tertentu misalnya untuk kompilasi paket.
Martin Smith
@ MartinSmith Permintaan di mana saya menemukan masalah pada proyek ini jauh lebih kompleks daripada contoh SELECT 1, yang membutuhkan lebih banyak kompilasi overhead tetapi hanya membaca dari beberapa tabel. Saya mencoba mereproduksi kebuntuan jenis ini dengan pertanyaan yang lebih kompleks.
SqlWhale
@ TechKnowNothing Tentang berapa banyak baris yang Anda masukkan? Berapa kali per hari proses berjalan? Apakah pertanyaan lain SELECT dari tabel saat data dimuat?
Joe Obbish
@ Joobbish 1. Saya tidak berpikir # baris adalah masalah di sini, kami hanya memiliki 4000 - 70000 untuk setiap permintaan dan tetapi mereka adalah data yang sangat teragregasi untuk penggunaan kubus. 2. Masih dalam tahap pengujian, seharusnya dijalankan sekali sehari. 3.Tidak ada lagi yang membaca dari tabel target.
SqlWhale
4

Anda memasukkan ke dalam dbo.TargetTabledari dua sesi dan keduanya menggunakan TABLOCKpetunjuk. Keduanya process9609dc8dan process5e13048proses memegang Sch-Sdan IXmengunci yang kompatibel satu sama lain sehingga kedua proses dapat bertahan pada waktu yang sama. Tetapi keduanya ingin mengkonversi IXkunci untuk Exclusive Xmengetik. Xkunci tidak kompatibel satu sama lain. Oleh karena itu, SQL server memilih salah satu sesi sebagai korban kebuntuan alih-alih menunggu satu sama lain.

Informasi kebuntuan dasar.

Bagan Kunci Kompatibilitas (Mesin Basis Data).

Mendeteksi dan Mengakhiri Deadlock.

SqlWorldWide
sumber