SELECT-UPDATE desenini kullanırken eşzamanlılığı yönetme


25

Aşağıdaki kodun sizde olduğunu varsayalım (lütfen bunun korkunç olduğunu dikkate almayın):

BEGIN TRAN;
DECLARE @id int
SELECT @id = id + 1 FROM TableA;
UPDATE TableA SET id = @id; --TableA must have only one row, apparently!
COMMIT TRAN;
-- @id is returned to the client or used somewhere else

Gözüme göre, bu eşzamanlılık düzgün yönetmiyor. Sırf bir işleminiz olduğu için, güncelleme bildiriminize gelmeden önce başkasının okuduğunuz değeri okumamayacağı anlamına gelmez.

Şimdi, kodu olduğu gibi bırakmak (bunun tek bir ifadeyle daha iyi ele alındığını veya otomatik bir öznitelik / kimlik sütunu kullanarak daha iyi işlendiğinin farkındayım), eşzamanlılığı düzgün bir şekilde işlemesini sağlamanın ve iki istemcinin aynı olmasına izin veren yarış koşullarını önlemenin kesin yolları nelerdir? kimlik değeri?

WITH (UPDLOCK, HOLDLOCK)SELECT'e bir ekleme yapmanın hile yapacağına eminim . SERIALIZABLE işlem yalıtım düzeyi (Başkasının tran bitene kadar ne yaptığını okumak için inkar beri de işin görünüyor ediyorum GÜNCELLEME . Bu yanlıştır Bkz Martin'in cevabı). Bu doğru mu? Her ikisi de eşit derecede iyi çalışır mı? Biri diğerine mi tercih edilir?

Kimlik güncellemesinden daha meşru bir şey yaptığınızı hayal edin - güncellemeniz gereken bir okumaya dayalı bir hesaplama. Bazıları yazacağınız, bazıları yazmayacağınız birçok tablo olabilir. Buradaki en iyi uygulama nedir?

Bu soruyu yazdıktan sonra kilitleme ipuçlarının daha iyi olacağını düşünüyorum çünkü o zaman sadece ihtiyacınız olan masaları kilitlemektesiniz ama birinin girişini takdir ediyorum.

PS Ve hayır, en iyi cevabı bilmiyorum ve gerçekten daha iyi bir anlayış elde etmek istiyor! :)


Sadece açıklama için: 2 müşterinin aynı değeri okumasını veya updatekullanılmayan verilere dayanarak yayınlamasını engellemek ister misiniz ? Daha sonra, rowversiongüncellenecek satırın okunduğundan beri değişip değişmediğini kontrol etmek için sütunu kullanabilirsiniz .
a1ex07

İlk müşterinin yeni değerine güncellenmeden önce ikinci bir müşterinin eski kimliği almasını istemiyoruz. Engellemeli.
ErikE

Yanıtlar:


11

Sadece SERIALIZABLEizolasyon seviyesi yönünü ele alıyoruz. Evet bu işe yarar, ancak kilitlenme riski vardır.

Her iki işlem de satırı aynı anda okuyabilir. Bir nesne Skilidi veya RangeS-Smasa yapısına bağlı indeks kilitleri alacağı için birbirlerini engellemeyeceklerdir ve bu kilitler uyumludur . Ancak, güncelleme için gerekli kilitleri ( sırasıyla nesne IXkilidi veya dizin RangeS-U) almaya çalışırken kilitlenmeye neden olacak şekilde birbirlerini engelleyecektir .

Açık bir UPDLOCKipucunun kullanılması, okumaları seri hale getirerek kilitlenme riskini önler.


+1 ancak: yığın tabloları için güncelleme kilitleriyle bile hala bir dönüşüm kilitlenmesi elde edebilirsiniz: sqlblog.com/blogs/alexander_kuznetsov/archive/2009/03/11/…
AK

Tuhaf, @alex. Ben aslında UPDLOCKing önce ne kilitlemek bulmaya çalışırken motorun bir yarış durumu ile ilgili olduğunu hayal ediyorum ...
ErikE

@ErikE - Alex makalesinde dönüşüm kilitlenme dönüştürme olduğu IXiçin Xyığın kendisinde. İlginçtir ki hiçbir satır kalifiye değildir, bu yüzden hiçbir satır kilitleri alınmaz. Neden Xkilit aldığından emin değilim .
Martin Smith,

11

Bence, sizin için en iyi yaklaşım, modülünüzü yüksek eşzamanlılığa maruz bırakmak ve kendiniz için görmek olacaktır. Bazen tek başına UPDLOCK yeterlidir ve HOLDLOCK'a gerek yoktur. Bazen sp_getapplock çok iyi sonuç veriyor. Burada herhangi bir battaniye ifadesi yapmazdım - bazen bir indeks daha ekler, tetikler veya indekslenmiş görünüm sonucu değiştirir. Test kodunu vurgulamamız ve duruma göre kendimiz görmemiz gerekiyor.

Birkaç stres testi örneği yazdım Burada

Düzenle: İç kişiler hakkında daha fazla bilgi için Kalen Delaney'in kitaplarını okuyabilirsiniz. Ancak, kitaplar diğer belgeler gibi senkronize edilmeyebilir. Ayrıca, dikkate alınması gereken çok fazla kombinasyon vardır: altı izolasyon seviyesi, birçok kilit tipi, kümelenmiş / kümelenmemiş indeksler ve başka ne olduğunu kim bilir. Bu çok fazla kombinasyon. Bunun da ötesinde, SQL Server kapalı kaynaktır, bu yüzden kaynak kodunu indiremeyiz, hata ayıklayamayız ve böyle bir şey yapamayız - bu nihai bilgi kaynağı olacaktır. Bir sonraki sürümden veya servis paketinden sonra herhangi bir şey eksik veya eski olabilir.

Bu nedenle, kendi stres testiniz olmadan sisteminizde neyin işe yarayacağına karar vermemelisiniz. Ne okuduysanız, neler olup bittiğini anlamanıza yardımcı olabilir, ancak okuduğunuz tavsiyenin sizin için işe yaradığını kanıtlamanız gerekir. Kimsenin senin için yapabileceğini sanmıyorum.


9

Bu özel durumda, bir UPDLOCKkilidin eklenmesi SELECTgerçekten de anomalileri önler. İşlem HOLDLOCKsüresince bir güncelleme kilidi tutulduğu için eklenmesi gerekli değildir, ancak geçmişte kendime (muhtemelen kötü) bir alışkanlık olarak dahil etmeyi itiraf ediyorum.

Bir ID güncellemesinden daha meşru bir şey yaptığınızı, güncellemeniz gereken bir okumayı temel alan bir hesaplama yaptığınızı hayal edin. Bazıları yazacağınız, bazıları yazmayacağınız birçok tablo olabilir. Buradaki en iyi uygulama nedir?

En iyi uygulama yok. Eşzamanlılık kontrolü seçiminiz, uygulamanın gereksinimlerine dayanmalıdır. Bazı uygulamaların / işlemlerin, her ne pahasına olursa olsun anomalilerden ve yanlışlıklardan kaçınarak, veritabanına münhasır sahiplik yapmış gibi yapılması gerekir. Diğer uygulamalar / işlemler birbirinden bir dereceye kadar girişime tolerans gösterebilir.

  • Bir web mağazasındaki bir ürün için bantlı bir stok seviyesinin (<5, 10+, 50+, 100+) alınması = kirli okuma (yanlış önemli değil).
  • Bu web mağazasında stok seviyesini kontrol etme ve azaltma = tekrarlanabilir okuma (biz satmadan önce hisseye sahip olmalıyız, negatif bir stok seviyesine sahip olmamalıyız).
  • Bankadaki mevcut hesabım ve tasarruf hesabım arasında nakit taşıma = seri hale getirilebilir (nakit paramı yanlış hesaplamayın ya da yanlış yere koymayın!).

Düzenleme: @ AlexKuznetsov'un yorumu soruyu yeniden okumamı ve cevabımdaki çok açık hatayı kaldırmamı istedi. Gece geç saatlerde gönderim yaparken kendi kendine not al.

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.