SQL Server Dizin Güncelleme Kilitlenmesi


13

Aynı anda çalıştırıldığında bir kilitlenmeye neden olan 2 sorgularım var.

Sorgu 1 - bir dizinde (index1) bulunan bir sütunu güncelleyin:

update table1 set column1 = value1 where id = @Id

Tablo1'de X-Lock'u alır, ardından index1'de bir X-Lock'u dener.

Sorgu 2:

select columnx, columny, etc from table1 where {some condition}

Dizin1'de bir S-Kilidi alır ve ardından tablo1'de bir S-Kilidi dener.

Aynı sorguları korurken kilitlenmeyi önlemenin bir yolu var mı? Örneğin, tablo ve dizin erişiminin aynı sırada olduğundan emin olmak için güncellemeden önce güncelleme işlemindeki dizine bir X-Kilidi alabilir miyim?

İzolasyon seviyesi Okuma Taahhütlüdür. Dizinler için satır ve sayfa kilitleri etkinleştirilir. Aynı kaydın her iki sorguya da katılması mümkündür - parametreleri göstermediği için kilitlenme grafiğinden anlatamam.

Kilitlenme grafiği

Yanıtlar:


11

Aynı sorguları korurken kilitlenmeyi önlemenin bir yolu var mı?

Kilitlenme grafiği, bu özel kilitlenmenin bir yer işareti aramasıyla ilişkili bir dönüşüm kilitlenmesi olduğunu gösterir (bu durumda bir RID araması):

Kilitlenme grafiği

Soruda belirtildiği gibi, genel kilitlenme riski ortaya çıkar çünkü sorgular farklı kaynaklarda aynı kaynaklar üzerinde uyumsuz kilitler elde edebilir. SELECTSorgu oysa nedeniyle RID arama masaya önce endeksi erişmesi gereken UPDATEsonra, tablo ilk sorgu tuşelere indeksi.

Kilitlenmenin giderilmesi için kilitlenme bileşenlerinden birinin kaldırılması gerekir. Ana seçenekler şunlardır:

  1. Kümelenmemiş dizin kaplaması yaparak RID aramasından kaçının. SELECTSorgunuz 26 sütun döndürdüğünden , bu durum büyük olasılıkla pratik değildir .
  2. Kümelenmiş bir dizin oluşturarak RID aramasından kaçının. Bu, sütunda kümelenmiş bir dizin oluşturmayı içerir Proposal. Bu sütun, uniqueidentifierdaha geniş sorunlara bağlı olarak, kümelenmiş bir dizin için iyi bir seçim olabilecek veya olmayabilecek türde bir tür gibi görünse de, dikkate değerdir .
  3. READ_COMMITTED_SNAPSHOTVeya SNAPSHOTveritabanı seçeneklerini etkinleştirerek okurken paylaşılan kilitler almaktan kaçının . Bu, özellikle tasarlanmış engelleme davranışlarıyla ilgili olarak dikkatli testler yapılmasını gerektirir. Tetik kodunun ayrıca mantığın doğru çalıştığından emin olmak için test edilmesi gerekir.
  4. Sorgu READ UNCOMMITTEDiçin yalıtım düzeyini kullanarak okurken paylaşılan kilitler almaktan kaçının SELECT. Tüm olağan uyarılar geçerlidir.
  5. Özel bir uygulama kilidi kullanarak söz konusu iki sorguyu aynı anda yürütmekten kaçının (bkz. Sp_getapplock ).
  6. Eşzamanlılığı önlemek için tablo kilidi ipuçlarını kullanın. Bu, seçenek 5'ten daha büyük bir çekiçtir, çünkü yalnızca soruda tanımlanan iki sorguyu değil, diğer sorguları da etkileyebilir.

Tablo ve dizin erişiminin aynı sırada olduğundan emin olmak için güncellemeden önce bir şekilde güncelleme işleminde dizine X-Lock alabilir miyim

Güncellemeyi açık bir işlemde sararak ve güncellemeden önce kümelenmemiş dizin değeri üzerinde SELECTbir XLOCKipucu yaparak bunu deneyebilirsiniz . Bu, kümelenmemiş dizindeki mevcut değerin ne olduğunu kesin olarak bilmenize, yürütme planını doğru hale getirmenize ve bu ekstra kilidi almanın tüm yan etkilerini doğru bir şekilde tahmin etmenize bağlıdır. Ayrıca, yedek motorun, gereksiz olduğu düşünülürse kilidi almayı engelleyecek kadar akıllı olmamasına da bağlıdır .

Kısacası, bu prensipte uygulanabilir olsa da, tavsiye etmiyorum. Bir şeyi kaçırmak ya da yaratıcı yollarla kendini alt etmek çok kolaydır. Bu kilitlenmelerden gerçekten kaçınmanız gerekiyorsa (sadece onları tespit edip yeniden denemek yerine), yukarıda listelenen daha genel çözümlere bakmanızı öneririm.


Soruna daha fazla baktığımda, değişmeden bırakmak muhtemelen en iyisi. Aslında fark ettiğim daha yaygın bir problem.
Dale K

1

Ara sıra ortaya çıkan benzer bir sorunum var ve burada benim yaklaşımım.

  1. Seçime ekleyin set deadlock priority low;. Bu, bir kilitlenme oluştuğunda bu sorgunun kilitlenme kurbanı olmasına neden olur.
  2. Engelleme sorgularının tamamlanmasına izin vermek için kısa bir süre bekledikten / uyuduktan sonra, kilitlenme (veya zaman aşımı) nedeniyle başarısız olursa seçimi otomatik olarak yeniden denemek için uygulamanızdaki yeniden deneme mantığını kurun.

Not: selectAçık bir çoklu hesap işleminin parçasıysa, yalnızca başarısız olan ifadeyi değil, tüm işlemi yeniden denediğinizden emin olmanız gerekir, aksi takdirde beklenmedik sonuçlar alabilirsiniz. Bu bir tek ise, selecto zaman iyi, ama bir işlem içinde bildirimi xise n, o zaman sadece yeniden deneme nsırasında tüm ifadeleri yeniden deneyin emin olun .


Teşekkürler - sorgular varsayılan olarak kilitlenme kurbanlarıdır. Ve evet, zaten sağlam bir yeniden deneme mekanizmamız var.
Dale K
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.