SELECT… XLOCK İLE kullanmak için iyi nedenler?


11

Biri bir Keylock ve kilitlenme kurbanı haline XLOCK ipucu ile bir SELECT sorgusu içeren bazı yeniden meydana gelen kilitlenme ile karşı karşıya. Diğer ifade, ilk sorgu görünümünün bir parçası olan tablolardan birine bir INSERT.

Görünüm:

create view dbo.viewE
 as
    select * from dbo.E  
    where myValue > 13000 

Sorgu Seçin:

select * from dbo.viewE with (XLOCK) where A > GETUTCDATE() 

INSERT Bildirimi:

INSERT INTO [dbo].[E] (myValue,A) VALUES (10,GetDate())

Temel tablo dbo.E, yaklaşık 20 sütunda yaklaşık 3 milyon satır tutuyor, bazıları ntext.

Sorguları çıkararak ve iki işlemle elle simüle ederek, davranış yeniden üretilebilir. XLOCK seçimden kaldırılırsa davranış değişir.

Kilitlenme Grafiği:

<deadlock-list>
 <deadlock victim="process222222221">
  <process-list>
   <process id="process222222221" taskpriority="0" logused="0" waitresource="KEY: 5:72057604035644444 (ccdf51accc0c)" waittime="2522" ownerId="27202256401" transactionname="SELECT" lasttranstarted="2015-09-14T16:32:36.160" XDES="0x2f1ec5ca0" lockMode="RangeX-X" schedulerid="15" kpid="12936" status="suspended" spid="359" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2015-09-14T16:32:36.160" lastbatchcompleted="2015-09-14T16:32:36.160" clientapp="x" hostname="x" hostpid="14536" loginname="x" isolationlevel="serializable (4)" xactid="27202256401" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="48" sqlhandle="0x02000000611e4523142b2318c47c87313a9b2ba587ff3130">
        SELECT * FROM viewE WITH (XLOCK) WHERE A &lt; GetUtcDate()      </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
(@UICulture nvarchar(5))SELECT * FROM viewE WITH (XLOCK) WHERE A &lt; GetUtcDate()    </inputbuf>
   </process>
   <process id="process6022222" taskpriority="0" logused="161152" waitresource="KEY: 5:72057604035644444 (cd874c2ba438)" waittime="1370" ownerId="27202248438" transactionguid="0x8de5ccd6eeef67469c6234af59e44ca5" transactionname="DTCXact" lasttranstarted="2015-09-14T16:32:34.767" XDES="0x4aa0bf950" lockMode="RangeI-N" schedulerid="14" kpid="6636" status="suspended" spid="329" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2015-09-14T16:32:37.300" lastbatchcompleted="2015-09-14T16:32:37.300" clientapp="x" hostname="x" hostpid="14536" loginname="x" isolationlevel="read uncommitted (1)" xactid="27202248438" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="936" sqlhandle="0x020000004853462f09790a4ddedc0d574c2afa539aef1c0e">
     INSERT INTO [E] ([a], [b], [c],...) VALUES (@aDate, @bDate, @c, ...)
     </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>INSERT INTO [E] ([a], [b], [c],...) VALUES (@aDate, @bDate, @c, ...)
    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <keylock hobtid="72057604035644444" dbid="5" objectname="db.dbo.E" indexname="IX_index1" id="lock258b6dc80" mode="X" associatedObjectId="72057604035644444">
    <owner-list>
     <owner id="process6022222" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process222222221" mode="RangeX-X" requestType="wait"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057604035644444" dbid="5" objectname="db.dbo.E" indexname="IX_index1" id="lock7b145c400" mode="RangeX-X" associatedObjectId="72057604035644444">
    <owner-list>
     <owner id="process222222221" mode="RangeX-X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process6022222" mode="RangeI-N" requestType="wait"/>
    </waiter-list>
   </keylock>
  </resource-list>
 </deadlock>
</deadlock-list>

Ben bunu anlıyorum, temelde gerekli değerleri toplamak için kümelenmemiş ve kümelenmiş bir dizin kullanan ortaya çıkarılan bir dizin sorgusu neden bir KEYLOCK kilitlenme bakıyorum, değil mi?

Sorularım:

  1. İlgili gerekli NTEXT sütunları nedeniyle bir kaplama dizini oluşturamıyorum. Sıra sayısını büyük ölçüde azaltmak burada yardımcı olur mu?
  2. SELECT'in XLOCK ile yürütüldüğünü bilmememin iyi bir nedeni var mı? Kilitlenme XLOCK olmadan da olur mu?

Yanıtlar:


15

Ben bunu anlıyorum, temelde gerekli değerleri toplamak için kümelenmemiş ve kümelenmiş bir dizin kullanan ortaya çıkarılan bir dizin sorgusu neden bir KEYLOCK kilitlenme bakıyorum, değil mi?

Esasen, evet. Okuma işlemi (select) önce kümelenmemiş dizine, sonra kümelenmiş dizine (arama) erişir. Yazma işlemi (insert) önce kümelenmiş dizine, sonra da kümelenmemiş dizine erişir. Uyumsuz kilitler tutarak aynı kaynaklara farklı bir sırayla erişmek kilitlenmeye yol açabilir.

Sıra sayısını büyük ölçüde azaltmak burada yardımcı olur mu?

Bu belki daha az kaynak kilitli ve çünkü, operasyon daha çabuk tamamlanması eğiliminde olacaktır. Yardım ederse, kilitlenmeleri azaltabilir , ancak büyük olasılıkla bunları ortadan kaldırmaz (ancak okumaya devam edin).

SELECT'in XLOCK ile yürütüldüğünü bilmememin iyi bir nedeni var mı?

Pek sayılmaz. Bunun gibi kilit ipuçları genellikle bir sorunu azaltmak veya ortadan kaldırmak için umutsuz bir girişimde tecrit, kilitleme ve kilitlenmelerin nasıl çalıştığını tam olarak anlamayan insanlar tarafından tanıtılır.

Kilitlenme XLOCK olmadan da olur mu?

Hayır , eğer seçim gerçekte okunmamış izolasyonda çalışıyorsa, çünkü uyumsuz kilitler farklı bir sırada alınmaz (ve tutulmaz).

Evet , bir kilitleme izolasyon seviyesi kullanılırsa ve uyumsuz kilitler tutarsız bir düzende alınır ve tutulursa, örneğin, kümelenmemiş üzerinde paylaşılan (S), sonra okuma sırasında kümelenmiş S. Bu senaryoda bir kilitlenmenin ne kadar olası olduğu, kaç tane kilitin alındığına ve ne kadar süreyle tutulduğuna bağlıdır.

Tavsiye

Gerçekten göze çarpan şey (incelemede), seçme işleminin serileştirilebilir yalıtım altında çalıştığıdır . Bu, çerçeveniz tarafından veya DTC'nin (Dağıtılmış İşlem Düzenleyicisi) kullanılması nedeniyle ayarlanmış olabilir - kilitlenme grafiğindeki transactionname = "DTCXact" bölümüne bakın. Bunun nedenlerine bakmalı ve mümkünse değiştirmelisiniz.

Serileştirilebilen bu artış olmadan, XLOCKipucunun kaldırıldığı varsayılarak, bu kilitlenmenin gerçekleşmeme olasılığı çok yüksektir . Bununla birlikte, çok az tutarlılık garantisi ile birlikte gelen okunmamış taahhütler altında okuyorsunuz .

Başvurunuz ve SQL Server kod değişen, satır sürümlerini okuma tahammül Eğer kararlı anlık yalıtım okumak (RCSI) ya da anlık yalıtım (SI) okur için de kilitlenme (önleyeceğini XLOCKtutarlı sunarken, kaldırıldı!), Nokta-in taahhüt edilen verinin zaman görünümü. Bu aynı zamanda serileştirilebilir izolasyondan kaçınabileceğinizi varsayar.

Sonuçta, XLOCKipucu olduğunu üretkenliği, ama sen gerçekten seri hale getirilebilir yalıtım seviyesinin kullanılması nedeni içine bakmak gerekir. trancount = 2Ayrıca ilginç - belki istemeden yuvalama işlemler burada. Kontrol edilecek başka bir şey.


2
  1. Sıra sayısını büyük ölçüde azaltmak çıkmazı alma olasılığını azaltacaktır, ancak tamamen ortadan kalkmayacaktır.

Basit bir ifadeyle seçim, önce seçilecek satırları belirlemek için dizini kullanır, daha sonra ekleme bir satır eklerken satırları getirir, ardından (XLOCKED) dizinini güncellemeye çalışır.

  1. Uygulama geliştiricileri, daha sonra veriler üzerinde bir güncelleme yapmak istedikleri aynı işlemde XLOCK kullanma eğilimindedir. Bu, kimsenin altındaki verileri güncelleyememesini sağlar. XLOCK'un gerekli olup olmadığını görmek için uygulamanın ne yaptığını araştırırım.

Bunu söyledikten sonra, XLOCK'u kaldırmak muhtemelen sorunu çözmez. SELECT yine de dizinde paylaşılan bir kilit çıkarır ve INSERT bir XLOCK'un güncellemesini ister. Paylaşılan bir kilit ve bir XLOCK nesne üzerinde birlikte bulunamaz, bu yüzden hala bir kilitlenme elde edersiniz. IX_Index1, MyValue veya A veya her ikisi olmalıdır.

Bu tür kilitlenme genellikle kötü tasarlanmış dizinler ve / veya çok fazla dizin nedeniyle oluşur. Ya da kötü yazılmış kod. En iyi seçeneğiniz, seçimin başka bir dizin kullanmak için yeniden yazılabilir olup olmadığını görmek.

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.