Silme / yerleştirme işleminde aynı kilitli kümelenmiş Anahtar (NHibernate ile) üzerinde SQL Kilitlenme


29

Bu kilitlenme sorunu üzerinde birkaç gündür çalışıyorum ve ne yaparsam yapayım ya da böyle devam ediyor.

Birincisi, genel öncül: Bir-birçok ilişkimizde VisitItems ile ziyaretlerimiz var.

VisitItems ilgili bilgi:

CREATE TABLE [BAR].[VisitItems] (
    [Id]                INT             IDENTITY (1, 1) NOT NULL,
    [VisitType]         INT             NOT NULL,
    [FeeRateType]       INT             NOT NULL,
    [Amount]            DECIMAL (18, 2) NOT NULL,
    [GST]               DECIMAL (18, 2) NOT NULL,
    [Quantity]          INT             NOT NULL,
    [Total]             DECIMAL (18, 2) NOT NULL,
    [ServiceFeeType]    INT   NOT NULL,
    [ServiceText]       NVARCHAR (200)  NULL,
    [InvoicingProviderId] INT   NULL,
    [FeeItemId]        INT             NOT NULL,
    [VisitId]          INT             NULL,
    [IsDefault] BIT NOT NULL DEFAULT 0, 
    [SourceVisitItemId] INT NULL, 
    [OverrideCode] INT NOT NULL DEFAULT 0, 
    [InvoiceToCentre] BIT NOT NULL DEFAULT 0, 
    [IsSurchargeItem] BIT NOT NULL DEFAULT 0, 
    CONSTRAINT [PK_BAR.VisitItems] PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_BAR.VisitItems_BAR.FeeItems_FeeItem_Id] FOREIGN KEY ([FeeItemId]) REFERENCES [BAR].[FeeItems] ([Id]),
    CONSTRAINT [FK_BAR.VisitItems_BAR.Visits_Visit_Id] FOREIGN KEY ([VisitId]) REFERENCES [BAR].[Visits] ([Id]), 
    CONSTRAINT [FK_BAR.VisitItems_BAR.VisitTypes] FOREIGN KEY ([VisitType]) REFERENCES [BAR].[VisitTypes]([Id]), 
    CONSTRAINT [FK_BAR.VisitItems_BAR.FeeRateTypes] FOREIGN KEY ([FeeRateType]) REFERENCES [BAR].[FeeRateTypes]([Id]),
    CONSTRAINT [FK_BAR.VisitItems_CMN.Users_Id] FOREIGN KEY (InvoicingProviderId) REFERENCES [CMN].[Users] ([Id]),
    CONSTRAINT [FK_BAR.VisitItems_BAR.VisitItems_SourceVisitItem_Id] FOREIGN KEY ([SourceVisitItemId]) REFERENCES [BAR].[VisitItems]([Id]),
    CONSTRAINT [CK_SourceVisitItemId_Not_Equal_Id] CHECK ([SourceVisitItemId] <> [Id]),
    CONSTRAINT [FK_BAR.VisitItems_BAR.OverrideCodes] FOREIGN KEY ([OverrideCode]) REFERENCES [BAR].[OverrideCodes]([Id]),
    CONSTRAINT [FK_BAR.VisitItems_BAR.ServiceFeeTypes] FOREIGN KEY ([ServiceFeeType]) REFERENCES [BAR].[ServiceFeeTypes]([Id])
)

CREATE NONCLUSTERED INDEX [IX_FeeItem_Id]
    ON [BAR].[VisitItems]([FeeItemId] ASC)

CREATE NONCLUSTERED INDEX [IX_Visit_Id]
    ON [BAR].[VisitItems]([VisitId] ASC)

Ziyaret bilgisi:

CREATE TABLE [BAR].[Visits] (
    [Id]                     INT            IDENTITY (1, 1) NOT NULL,
    [VisitType]              INT            NOT NULL,
    [DateOfService]          DATETIMEOFFSET  NOT NULL,
    [InvoiceAnnotation]      NVARCHAR(255)  NULL ,
    [PatientId]              INT            NOT NULL,
    [UserId]                 INT            NULL,
    [WorkAreaId]             INT            NOT NULL, 
    [DefaultItemOverride] BIT NOT NULL DEFAULT 0, 
    [DidNotWaitAdjustmentId] INT NULL, 
    [AppointmentId] INT NULL, 
    CONSTRAINT [PK_BAR.Visits] PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_BAR.Visits_CMN.Patients] FOREIGN KEY ([PatientId]) REFERENCES [CMN].[Patients] ([Id]) ON DELETE CASCADE,
    CONSTRAINT [FK_BAR.Visits_CMN.Users] FOREIGN KEY ([UserId]) REFERENCES [CMN].[Users] ([Id]),
    CONSTRAINT [FK_BAR.Visits_CMN.WorkAreas_WorkAreaId] FOREIGN KEY ([WorkAreaId]) REFERENCES [CMN].[WorkAreas] ([Id]), 
    CONSTRAINT [FK_BAR.Visits_BAR.VisitTypes] FOREIGN KEY ([VisitType]) REFERENCES [BAR].[VisitTypes]([Id]),
    CONSTRAINT [FK_BAR.Visits_BAR.Adjustments] FOREIGN KEY ([DidNotWaitAdjustmentId]) REFERENCES [BAR].[Adjustments]([Id]), 
);

CREATE NONCLUSTERED INDEX [IX_Visits_PatientId]
    ON [BAR].[Visits]([PatientId] ASC);

CREATE NONCLUSTERED INDEX [IX_Visits_UserId]
    ON [BAR].[Visits]([UserId] ASC);

CREATE NONCLUSTERED INDEX [IX_Visits_WorkAreaId]
    ON [BAR].[Visits]([WorkAreaId]);

Birden çok kullanıcı, VisitItems tablosunu aynı anda aşağıdaki şekilde güncellemek ister:

Ayrı bir web isteği, VisitItems ile bir Ziyaret (genellikle 1) yaratacaktır. Sonra (sorun isteği):

  1. Web isteği gelir, NHibernate oturumunu açar, NHibernate işlemini başlatır (READ_COMMITTED_SNAPSHOT ile Tekrarlanabilir Okuma özelliğini kullanarak).
  2. Belirli bir ziyaret için tüm ziyaret öğelerini VisitId ile okuyun .
  3. Kod, öğelerin hala alakalı olup olmadığını veya karmaşık kurallar kullanarak yenilere ihtiyacımız olup olmadığını değerlendirir (çok az uzun süren, örneğin 40ms).
  4. Kod eklenmesi gereken 1 madde bulur, NHibernate Visit.VisitItems.Add (..) kullanarak ekler.
  5. Kod, bir öğenin silinmesi gerektiğini (az önce eklediğimiz öğeyi değil) tanımlar, NHibernate Visit.VisitItems.Remove (item) kullanarak kaldırır.
  6. Kod işlemi taahhüt eder

Bir araçla, gelecekteki bir üretim ortamında gerçekleşmesi muhtemel olan 12 eşzamanlı isteği simüle ediyorum.

[EDIT] Talep üzerine, kısa tutmak için buraya eklediğim birçok araştırma detayını kaldırdım.

Çok fazla araştırmadan sonra, bir sonraki adım, farklı bir dizindeki ipucunu, nerede, yan tümcesinde kullanılandan (yani, birincil anahtar, silme için kullanıldığından beri) kullanılan bir ipucunu nasıl kilitleyebileceğimi düşünmekti. :

var items = (List<VisitItem>)_session.CreateSQLQuery(@"SELECT * FROM BAR.VisitItems WITH (XLOCK, INDEX([PK_BAR.VisitItems]))
        WHERE VisitId = :visitId")
        .AddEntity(typeof(VisitItem))
        .SetParameter("visitId", qi.Visit.Id)
        .List<VisitItem>();

Bu, kilitlenmeleri sık sık hafifletti, ancak hala oluyorlardı. Ve burada kaybolmaya başladığım yer:

Üç özel kilit?

<deadlock-list>
  <deadlock victim="process3f71e64e8">
    <process-list>
      <process id="process3f71e64e8" taskpriority="0" logused="0" waitresource="KEY: 5:72057594071744512 (a5e1814e40ba)" waittime="3812" ownerId="8004520" transactionname="user_transaction" lasttranstarted="2015-12-14T10:24:58.010" XDES="0x3f7cb43b0" lockMode="X" schedulerid="1" kpid="15788" status="suspended" spid="63" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2015-12-14T10:24:58.013" lastbatchcompleted="2015-12-14T10:24:58.013" lastattention="1900-01-01T00:00:00.013" clientapp=".Net SqlClient Data Provider" hostname="ABC" hostpid="10016" loginname="bsapp" isolationlevel="repeatable read (3)" xactid="8004520" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
        <executionStack>
          <frame procname="adhoc" line="1" stmtstart="18" stmtend="254" sqlhandle="0x0200000024a9e43033ef90bb631938f939038627209baafb0000000000000000000000000000000000000000">
            unknown
          </frame>
          <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
            unknown
          </frame>
        </executionStack>
        <inputbuf>
          (@p0 int)SELECT * FROM BAR.VisitItems WITH (XLOCK, INDEX([PK_BAR.VisitItems]))
          WHERE VisitId = @p0
        </inputbuf>
      </process>
      <process id="process4105af468" taskpriority="0" logused="1824" waitresource="KEY: 5:72057594071744512 (8194443284a0)" waittime="3792" ownerId="8004519" transactionname="user_transaction" lasttranstarted="2015-12-14T10:24:58.010" XDES="0x3f02ea3b0" lockMode="S" schedulerid="8" kpid="15116" status="suspended" spid="65" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2015-12-14T10:24:58.033" lastbatchcompleted="2015-12-14T10:24:58.033" lastattention="1900-01-01T00:00:00.033" clientapp=".Net SqlClient Data Provider" hostname="ABC" hostpid="10016" loginname="bsapp" isolationlevel="repeatable read (3)" xactid="8004519" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
        <executionStack>
          <frame procname="adhoc" line="1" stmtstart="18" stmtend="98" sqlhandle="0x0200000075abb0074bade5aa57b8357410941428df4d54130000000000000000000000000000000000000000">
            unknown
          </frame>
          <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
            unknown
          </frame>
        </executionStack>
        <inputbuf>
          (@p0 int)DELETE FROM BAR.VisitItems WHERE Id = @p0
        </inputbuf>
      </process>
    </process-list>
    <resource-list>
      <keylock hobtid="72057594071744512" dbid="5" objectname="BAR.VisitItems" indexname="PK_BAR.VisitItems" id="lock449e27500" mode="X" associatedObjectId="72057594071744512">
        <owner-list>
          <owner id="process4105af468" mode="X"/>
        </owner-list>
        <waiter-list>
          <waiter id="process3f71e64e8" mode="X" requestType="wait"/>
        </waiter-list>
      </keylock>
      <keylock hobtid="72057594071744512" dbid="5" objectname="BAR.VisitItems" indexname="PK_BAR.VisitItems" id="lock46a525080" mode="X" associatedObjectId="72057594071744512">
        <owner-list>
          <owner id="process3f71e64e8" mode="X"/>
        </owner-list>
        <waiter-list>
          <waiter id="process4105af468" mode="S" requestType="wait"/>
        </waiter-list>
      </keylock>
    </resource-list>
  </deadlock>
</deadlock-list>

Sonuçta ortaya çıkan sorgu sayısının izleri buna benzer.
[EDIT] Whoa. Ne hafta ama. İzlemeyi, kilitlenmeye yol açacağını düşündüğüm ilgili ifadenin düzenlenmemiş iziyle güncelleştirdim.

exec sp_executesql N'SELECT * FROM BAR.VisitItems WITH (XLOCK, INDEX([PK_BAR.VisitItems]))
                WHERE VisitId = @p0',N'@p0 int',@p0=3826
go
exec sp_executesql N'SELECT visititems0_.VisitId as VisitId1_, visititems0_.Id as Id1_, visititems0_.Id as Id37_0_, visititems0_.VisitType as VisitType37_0_, visititems0_.FeeItemId as FeeItemId37_0_, visititems0_.FeeRateType as FeeRateT4_37_0_, visititems0_.Amount as Amount37_0_, visititems0_.GST as GST37_0_, visititems0_.Quantity as Quantity37_0_, visititems0_.Total as Total37_0_, visititems0_.ServiceFeeType as ServiceF9_37_0_, visititems0_.ServiceText as Service10_37_0_, visititems0_.InvoiceToCentre as Invoice11_37_0_, visititems0_.IsDefault as IsDefault37_0_, visititems0_.OverrideCode as Overrid13_37_0_, visititems0_.IsSurchargeItem as IsSurch14_37_0_, visititems0_.VisitId as VisitId37_0_, visititems0_.InvoicingProviderId as Invoici16_37_0_, visititems0_.SourceVisitItemId as SourceV17_37_0_ FROM BAR.VisitItems visititems0_ WHERE visititems0_.VisitId=@p0',N'@p0 int',@p0=3826
go
exec sp_executesql N'INSERT INTO BAR.VisitItems (VisitType, FeeItemId, FeeRateType, Amount, GST, Quantity, Total, ServiceFeeType, ServiceText, InvoiceToCentre, IsDefault, OverrideCode, IsSurchargeItem, VisitId, InvoicingProviderId, SourceVisitItemId) VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15); select SCOPE_IDENTITY()',N'@p0 int,@p1 int,@p2 int,@p3 decimal(28,5),@p4 decimal(28,5),@p5 int,@p6 decimal(28,5),@p7 int,@p8 nvarchar(4000),@p9 bit,@p10 bit,@p11 int,@p12 bit,@p13 int,@p14 int,@p15 int',@p0=1,@p1=452,@p2=1,@p3=0,@p4=0,@p5=1,@p6=0,@p7=1,@p8=NULL,@p9=0,@p10=1,@p11=0,@p12=0,@p13=3826,@p14=3535,@p15=NULL
go
exec sp_executesql N'UPDATE BAR.Visits SET VisitType = @p0, DateOfService = @p1, InvoiceAnnotation = @p2, DefaultItemOverride = @p3, AppointmentId = @p4, ReferralRequired = @p5, ReferralCarePlan = @p6, UserId = @p7, PatientId = @p8, WorkAreaId = @p9, DidNotWaitAdjustmentId = @p10, ReferralId = @p11 WHERE Id = @p12',N'@p0 int,@p1 datetimeoffset(7),@p2 nvarchar(4000),@p3 bit,@p4 int,@p5 bit,@p6 nvarchar(4000),@p7 int,@p8 int,@p9 int,@p10 int,@p11 int,@p12 int',@p0=1,@p1='2016-01-22 12:37:06.8915296 +08:00',@p2=NULL,@p3=0,@p4=NULL,@p5=0,@p6=NULL,@p7=3535,@p8=4246,@p9=2741,@p10=NULL,@p11=NULL,@p12=3826
go
exec sp_executesql N'DELETE FROM BAR.VisitItems WHERE Id = @p0',N'@p0 int',@p0=7919
go

Şimdi kilitlenme grafikte gösterdiğinden beri kilitlemimin bir etkisi var gibi görünüyor. Ama ne? Üç özel kilit ve bir ortak kilit? Bu aynı nesne / anahtar üzerinde nasıl çalışır? Özel bir kilidiniz olduğu sürece, başka birinden ortak bir kilitleme yapamayacağınızı düşündüm. Ve tam tersi. Paylaşılan bir kilidiniz varsa, hiç kimse özel bir kilit elde edemez, beklemek zorundadır.

Sanırım burada, aynı masada birden fazla tuşa alındıklarında kilitlerin nasıl çalıştığı hakkında daha derin bir anlayışım yok.

İşte denediğim bazı şeyler ve etkileri:

  • Lock deyimine IX_Visit_Id dizininde başka bir ipucu ipucu eklendi. Değişiklik yok
  • IX_Visit_Id'ye (VisitItem sütununun kimliği) ikinci bir sütun eklendi; çok uzaklaştı ama yine de denedi. Değişiklik yok
  • Okuma seviyesini tekrar değiştirmeyi kabul etti (projemizde varsayılan olarak), kilitlenmeler hala devam ediyor
  • Serileştirilebilir Yalıtım seviyesi değiştirildi. Deadlock hala devam ediyor, ama daha da kötüsü (farklı grafikler). Zaten bunu yapmak istemiyorum.
  • Bir masa kilidinin alınması onları (belli ki) ortadan kaldırır, fakat bunu kim yapmak ister?
  • Kötümser bir uygulama kilidinin alınması (sp_getapplock kullanarak) çalışır, ancak bu, masa kilidiyle aynı şeydir, bunu yapmak istemezsiniz.
  • READPAST ipucunu XLOCK ipucuna eklemek fark yaratmadı
  • Dizinde ve PK'de Sayfa Kilidi'ni kapattım, fark yok
  • XLOCK ipucuna ROWLOCK ipucu ekledim, hiçbir değişiklik yapmadım

NHibernate hakkında bazı yan not: Kullanılmasının ve çalıştığını anlamanın yolu, yapmamaya çalıştığımız floş dediğiniz sürece, sql ifadelerini gerçekten çalıştırmak için gerekli olana kadar önbelleğe almasıdır. Bu nedenle ifadelerin çoğu (örneğin tembel yüklü VisitItems Toplam Listesi => Visit.VisitItems) yalnızca gerekli olduğunda yürütülür. İşlemimden yapılan gerçek güncelleme ve silme bildirimlerinin çoğu, işlem tamamlandığında (yukarıdaki sql izlemesinden açıkça görüleceği gibi) sonunda yürütülür. Gerçekten yürütme emri üzerinde kontrolüm yok; NHibernate ne zaman ne yapılacağına karar verir. İlk kilit deyimim gerçekten yalnızca bir geçici çözüm.

Ayrıca, lock ifadesiyle, yalnızca kullanılmayan bir listedeki öğeleri okuyorum (NHibernate'in söyleyebileceğim kadar çalışmasının gerekmediği için Visit nesnesindeki VisitItems listesini geçersiz kılmaya çalışmıyorum). Bu yüzden listeyi ilk önce özel ifadeyle okuduğum halde, NHibernate listeyi yine proxy nesne koleksiyonuna tekrar yükleyecektir.

Ama bu önemli olmamalı, değil mi? Anahtar zaten kilitlendi mi? Tekrar yüklemek bunu değiştirmeyecek mi?

Son bir not olarak, açıklığa kavuşturmak için belki: Her işlem önce VisitItems ile kendi Ziyaretini ekliyor, sonra içeri giriyor ve onu değiştiriyor (silme ve ekleme ile kilitlenmeyi tetikleyecek). Testlerimde, aynı Visit ya da VisitItems'in aynısını değiştiren hiçbir işlem yoktur.

Buna daha fazla nasıl yaklaşılacağı hakkında fikri olan var mı? Akıllıca bir şekilde bu sorunu çözmeyi deneyebileceğim bir şey var mı (masa kilitleri vs.)? Ayrıca, bu tripple-x kilidinin neden aynı nesnede mümkün olduğunu öğrenmek istiyorum. Anlamadım

Bulmacayı çözmek için daha fazla bilgi gerekirse lütfen bana bildirin.

[EDIT] Sorumu, iki tablo için DDL ile güncelledim.

Ayrıca beklenti hakkında açıklama yapmam istendi: Evet, burada bir kaç kilitlenme var ve sorun yok, tekrar deneriz veya kullanıcının tekrar göndermesini isteriz (genellikle konuşma). Ancak 12 eşzamanlı kullanıcıyla şu anki sıklıkta, en fazla her birkaç saatte bir tane olmasını beklerdim. Şu anda dakikada birkaç kez açılırlar.

Buna ek olarak, gerçekte kullanmadığımız iç içe geçmiş işlemlerle ilgili bir sorun olduğunu gösterebilecek olan trancount = 2 hakkında daha fazla bilgi edindim. Bunu da araştırıp sonuçları burada belgeleyeceğim.


2
SELECT * kullanmayın. Sorunlarına katkı sağlayan bir faktör olabilir. Bkz stackoverflow.com/questions/3639861/...
JamieSee

Ayrıca, SELECT OBJECT_NAME(objectid, dbid) AS objectname, * FROM sys.dm_exec_sql_text(0x0200000024a9e43033ef90bb631938f939038627209baafb0000000000000000000000000000000000000000)gerçekte neyin yürütülmekte olduğunu belirlemek için her executionStack çerçevesindeki sqlhandle'ı çalıştırın.
JamieSee

Belki de bir karmaşaya mı çarpıyorsunuz? dba.stackexchange.com/questions/80088/insert-only-deadlocks/…
Johnboy

Hey millet, korkarım artık bu projenin bir parçası değilim: - /, bu yüzden önerilerinizi deneyemiyorum. Bununla birlikte, konuyu araştırabilmeleri için ipliği ve tüm bilgileri bazı ekip üyelerine ilettim.
Ben

Size yardımcı olabilecek daha fazla kilitlenme bilgisi almak için PowerShell betiğimi bu sorunun cevabını kullanabilirsiniz. Özellikle, "bilinmeyen" yığın çerçeveleriniz için SQL deyimi bilgilerini alır. dba.stackexchange.com/questions/28996/…
JamieSee

Yanıtlar:


2

Bu etki için birkaç yorum yaptım, ancak Yinelenebilir Okuma işlemi yalıtım düzeyini Oku Taahhütlü Anlık Görüntüsü ile birleştirdiğinizde istenen sonuçları aldığınızdan emin değilim.

Kilitlenme listenizde bildirilen TIL, tekrarlanan bir okumadır; Okuma Taahhüt'ten daha kısıtlayıcıdır ve tanımladığınız akış göz önüne alındığında, kilitlenmelere neden olabilir.

Yapmaya çalıştığınız şey, DB TIL'inizin tekrarlanabilir okunabilir kalmasını sağlamaktır, ancak işlemi, anlık bir TIL'yi belirli bir işlem yalıtım düzeyi ifadesinde açıkça kullanacak şekilde ayarlamaktır. Referans: https://msdn.microsoft.com/en-us/library/ms173763.aspx Öyleyse, yanlış bir şey olması gerektiğini düşünüyorum. NHibernate'e aşina değilim, ancak burada referans var gibi görünüyor: http://www.anujvarma.com/fluent-nhibernate-setting-database-transaction-isolation-level/

Uygulamanızın mimarisi izin veriyorsa, bir seçenek db düzeyinde okunan anlık görüntüyü denemek olabilir ve yine de kilitlenmeye devam ederseniz, satır sürümüyle anlık görüntüyü etkinleştirin. NOT: Bunu yaparsanız, anlık görüntüyü etkinleştirirseniz (satır sürümleme) tempdb kurulumunuzu yeniden düşünmeniz gerekir. İhtiyacın olursa sana her türlü materyali bulabilirim - bana bildirin.


2

Birkaç düşüncem var. Her şeyden önce, kilitlenmeleri önlemenin en kolay yolu her zaman aynı sırayla kilit almaktır. Bu, açık işlemleri kullanan farklı kodların aynı sıradaki nesnelere erişmesi gerektiği anlamına gelir, ancak ayrıca açık bir işlemdeki anahtarla tek tek satırlara erişilmesi de bu anahtar üzerinde sıralanmalıdır. Visit.VisitItemsYapmadan önce Addveya Deletebu durumda sıralayacağım çok büyük bir koleksiyon olmadığı sürece PK'sına göre sıralamayı deneyin SELECT.

Sıralama muhtemelen burada senin sorunun değil. 2 iş parçacığının VisitItemIDbelirli bir s için paylaşılan kilitleri tuttuğunu VisitIDve iş parçasının A DELETEiş parçasının B bitinceye kadar olmayacağı paylaşılan kilidini serbest bırakana kadar tamamlayamayacağını tahmin ediyorum DELETE. Uygulama kilitleri burada çalışacak ve yalnızca yöntemle engelledikleri ve diğerlerinin SELECTde iyi çalışacağı için tablo kilitleri kadar kötü değil . Ayrıca Visit, verilenler için masaya özel bir kilit de alabilirsiniz , VisitIDancak yine de, bu potansiyel olarak geçersiz sayılır.

Sabit silme işleminizi yumuşak bir silmeye ( UPDATE ... SET IsDeleted = 1kullanmak yerine DELETE) dönüştürmenizi ve bu kayıtları daha sonra toplu olarak temiz işlem kullanmayan bir temizleme işi kullanarak temizlemenizi öneririm . Bu açıkça, silinen bu satırları yoksaymak için başka bir kodun yeniden düzenlenmesini gerektirecektir, ancak açık DELETEbir işleme dahil edilen işlemlerde tercih edilen yöntemim SELECT.

İşlemden SELECTişlemi kaldırabilir ve iyimser eşzamanlılık modeline geçebilirsiniz. Entity framework bunu ücretsiz yapar, NHibernate hakkında emin değil. DELETE0 sıranız etkilendiğinde , EF, iyimser bir eşzamanlılık istisnasına yol açar.


1

VisitItems'ta herhangi bir değişiklik yapmadan önce, Visits güncellemesini taşımayı denediniz mi? Bu x-lock "alt" satırları korumalıdır.

Tamamen kilitlenmiş bir iz sürmek (ve insan tarafından okunabilir hale dönüştürmek) yapmak çok fazla iştir, ancak diziyi daha net gösterebilir.



-1

HAZIRLANMIŞ SNAPSHOT ON OKU, HAZIRLANMIŞ ISOLATION LEVEL (HAZIRLANMIŞ ISOLATION LEVEL) uygulamasında çalışan her bir işlemin HAZIRLANMIŞ SNAPSHOT olarak hareket edeceği anlamına gelir.

Bu, okuyucuların yazarları engellemeyeceği ve yazarların okuyucuları engellemeyeceği anlamına gelir.

Tekrarlanabilir okuma işlemi yalıtım seviyesi kullanıyorsunuz, bu yüzden kilitlenmeye sahipsiniz. Okuma Taahhüdü (anlık görüntü olmadan) satırların / sayfaların kilitlerini ifadenin sonuna kadar tutar , ancak Yinelenebilir Okuma işlemi işlemin sonuna kadar kilitleri tutar .

Kilitlenme grafiğinize bakarsanız, bir "S" kilidi aldığını görebilirsiniz. Sanırım bu ikinci noktada kilit -> "Belirli bir ziyaret için tüm ziyaret öğelerini VisitId tarafından okuyun."

  1. NHibernate bağlantınızın işlem yalıtım seviyesini Okuma Taahhüdü olarak değiştirin
  2. 2. puanınız için sorguyu analiz etmeniz ve visitID sütununuzda bir endeks varsa PK’nın neden kilitleri aldığını anlamanız gerekir (bunun nedeni dizininizde eksik olan sütunlar olabilir).
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.