डिलीट / इंसर्ट पर SQL डेडलॉक उसी एक्सक्लूसिवली लॉक क्लस्टर्ड की (NHibernate के साथ) पर


29

मैं काफी दिनों से इस गतिरोध के मुद्दे पर काम कर रहा हूं और कोई फर्क नहीं पड़ता कि मैं क्या करता हूं, यह एक तरह से या किसी अन्य तरीके से बना रहता है।

सबसे पहले, सामान्य आधार: हम एक से कई संबंधों में VisitItems के साथ विज़िट करते हैं।

प्रासंगिक जानकारी पर जाएँ:

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)

जानकारी पर जाएँ:

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]);

एकाधिक उपयोगकर्ता निम्नलिखित तरीके से समवर्ती यात्रा की तालिका अद्यतन करना चाहते हैं:

एक अलग वेब रिक्वेस्ट विजिट इट्स (आमतौर पर 1) के साथ एक विजिट बनाएगी। तब (समस्या अनुरोध):

  1. वेब अनुरोध आता है, NHibernate सत्र खोलता है, NHibernate लेनदेन शुरू करता है (READ_COMMITTED_SNAPSHOT के साथ दोहराए जाने योग्य पढ़ें)।
  2. VisitId द्वारा दी गई यात्रा के लिए सभी विज़िट आइटम पढ़ें ।
  3. कोड का आकलन है कि क्या आइटम अभी भी प्रासंगिक हैं या अगर हमें जटिल नियमों का उपयोग करके नए लोगों की आवश्यकता है (इसलिए थोड़ा लंबा चलना, जैसे 40ms)।
  4. कोड 1 आइटम को जोड़ने की जरूरत है, इसे NHibernate Visit.VisitItems.Add (..) का उपयोग करके जोड़ता है
  5. कोड पहचानता है कि एक आइटम को हटाने की जरूरत है (न कि जिसे हमने अभी जोड़ा है), इसे NHibernate Visit.VisitItems.Remove (आइटम) का उपयोग करके हटाता है।
  6. कोड लेन-देन करता है

एक उपकरण के साथ मैं 12 समवर्ती अनुरोधों का अनुकरण करता हूं जो भविष्य के उत्पादन वातावरण में होने की काफी संभावना है।

[संपादित करें] अनुरोध पर, मैंने इसे रखने के लिए बहुत सारे जांच विवरण हटा दिए हैं।

बहुत सारे शोधों के बाद अगला कदम यह सोचने का था कि मैं एक अलग सूचकांक पर संकेत को कैसे बंद कर सकता हूं जिसमें इस्तेमाल किया गया खंड (यानी प्राथमिक कुंजी, क्योंकि यह विलोपन के लिए उपयोग किया जाता है), इसलिए मैंने अपना लॉक स्टेटमेंट बदल दिया :

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>();

इसने गतिरोध को थोड़ा कम कर दिया, लेकिन वे अभी भी हो रहे थे। और यहाँ है जहाँ मैं खो जाना शुरू कर रहा हूँ:

तीन अनन्य ताले?

<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>

परिणामी प्रश्नों की एक संख्या इस तरह दिखती है।
[संपादित करें] वाह। क्या सप्ताह है। मैंने अब प्रासंगिक विवरण के अप्रमाणित ट्रेस के साथ ट्रेस को अपडेट किया है जो मुझे लगता है कि गतिरोध का कारण बनता है।

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

अब मेरे लॉक का असर दिख रहा है क्योंकि यह डेडलॉक ग्राफ में दिखाई दे रहा है। पर क्या? तीन अनन्य ताले और एक साझा ताला? कैसे एक ही वस्तु / कुंजी पर काम करता है? मुझे लगा कि जब तक आपके पास एक विशेष ताला है, तब तक आपको किसी और से साझा ताला नहीं मिल सकता है? और दूसरा रास्ता। यदि आपके पास साझा लॉक है, तो कोई भी विशेष लॉक प्राप्त नहीं कर सकता है, उन्हें इंतजार करना होगा।

मुझे लगता है कि मुझे यहाँ कुछ गहरी समझ की कमी है कि ताले कैसे काम करते हैं जब उन्हें एक ही टेबल पर कई कुंजियों पर ले जाया जाता है।

यहाँ कुछ चीजें मैंने कोशिश की हैं और उनका प्रभाव है:

  • IX_Visit_Id पर एक और सूचकांक संकेत को लॉक स्टेटमेंट में जोड़ा गया। कोई परिवर्तन नहीं होता है
  • IX_Visit_Id (विजिट इट कॉलम) की दूसरी कॉलम को जोड़ा; दूर से लाया, लेकिन वैसे भी कोशिश की। कोई परिवर्तन नहीं होता है
  • परिवर्तित अलगाव वापस पढ़ने के लिए प्रतिबद्ध (हमारी परियोजना में डिफ़ॉल्ट), गतिरोध अभी भी हो रहा है
  • परिवर्तनशील स्तर को परिवर्तित स्तर। गतिरोध अभी भी हो रहा है, लेकिन बदतर (अलग रेखांकन)। मैं वास्तव में ऐसा नहीं करना चाहता।
  • टेबल लॉक लेना उन्हें (स्पष्ट रूप से) दूर कर देता है, लेकिन कौन ऐसा करना चाहेगा?
  • निराशावादी एप्लिकेशन लॉक (sp_getapplock का उपयोग करके) काम करता है, लेकिन यह टेबल लॉक के समान ही है, ऐसा नहीं करना चाहते हैं।
  • READPAST संकेत को XLOCK संकेत में जोड़ने से कोई फर्क नहीं पड़ा
  • मैंने पेजलॉक को इंडेक्स और पीके पर बंद कर दिया है, कोई अंतर नहीं है
  • मैंने XLOCK संकेत में ROWLOCK संकेत जोड़ दिया है, इससे कोई फर्क नहीं पड़ता

NHibernate पर कुछ ओर ध्यान दें: जिस तरह से इसका उपयोग किया जाता है और मैं समझता हूं कि यह काम करता है कि यह sql वक्तव्यों को कैश करता है जब तक कि यह वास्तव में उन्हें निष्पादित करने के लिए आवश्यक नहीं लगता है, जब तक कि आप फ्लश नहीं कहते हैं, जो हम करने की कोशिश नहीं कर रहे हैं। इसलिए अधिकांश कथन (उदाहरण के लिए, लोड की गई एग्रीगेट सूची विज़िट विज़िट्स => विजिट.विसिटिटिज़म) को आवश्यक होने पर ही निष्पादित किया जाता है। मेरे लेन-देन से वास्तविक अपडेट और डिलीट स्टेटमेंट्स में से अधिकांश अंत में निष्पादित हो जाते हैं जब लेनदेन प्रतिबद्ध होता है (जैसा कि ऊपर दिए गए sql ट्रेस से स्पष्ट है)। मुझे वास्तव में निष्पादन आदेश पर कोई नियंत्रण नहीं है; NHibernate तय करता है कि कब क्या करना है। मेरा प्रारंभिक लॉक स्टेटमेंट वास्तव में केवल एक काम है।

इसके अलावा, लॉक स्टेटमेंट के साथ, मैं अभी आइटमों को अप्रयुक्त सूची में पढ़ रहा हूं (मैं विज़िट ऑब्जेक्ट पर विजिट इट्स लिस्ट को ओवरराइड करने की कोशिश नहीं कर रहा हूं क्योंकि यह नहीं है कि NHibernate को जहां तक ​​मैं बता सकता हूं, वहां काम करने वाला नहीं है)। भले ही मैं कस्टम विवरण के साथ सूची को सबसे पहले पढ़ता हूं, फिर भी NHibernate सूची को फिर से अपने प्रॉक्सी ऑब्जेक्ट संग्रह Visit.VisitItems में एक अलग sql कॉल का उपयोग करके लोड करेगा जिसे मैं ट्रेस में देख सकता हूं जब यह आलसी रूप से लोड होने का समय है।

लेकिन यह बात नहीं होनी चाहिए, है ना? मैं पहले से ही कहा कुंजी पर ताला है? यह लोड हो रहा है फिर से बदल नहीं होगा?

अंतिम नोट के रूप में, स्पष्ट करने के लिए शायद: प्रत्येक प्रक्रिया पहले VisitItems के साथ अपनी खुद की यात्रा को जोड़ रही है, फिर अंदर जाती है और इसे संशोधित करती है (जो डिलीट और इंसर्ट और डेडलॉक को ट्रिगर करेगी)। मेरे परीक्षणों में, कभी भी एक ही प्रक्रिया नहीं देखी गई है जो एक ही यात्रा या यात्रा कार्यक्रम है।

क्या किसी को इस बात का अंदाजा है कि इसे और आगे कैसे लाया जाए? कुछ भी मैं इसे स्मार्ट तरीके से प्राप्त करने की कोशिश कर सकता हूं (कोई टेबल लॉक आदि नहीं)? इसके अलावा, मैं सीखना चाहूंगा कि यह ट्रिपल-एक्स लॉक एक ही वस्तु पर भी क्यों संभव है। मुझे समझ नहीं आ रहा है।

कृपया मुझे बताएं कि क्या पहेली को हल करने के लिए किसी और जानकारी की आवश्यकता है।

[संपादित करें] मैंने दो तालिकाओं के लिए DDL के साथ प्रश्न को अद्यतन किया।

इसके अलावा मुझसे अपेक्षा पर स्पष्टीकरण मांगा गया था: हाँ, यहाँ कुछ गतिरोध हैं और ठीक हैं, हम केवल पुनः प्रयास करेंगे या उपयोगकर्ता को फिर से प्रस्तुत करेंगे (आम तौर पर बोल रहे हैं)। लेकिन 12 समवर्ती उपयोगकर्ताओं के साथ वर्तमान आवृत्ति पर, मुझे उम्मीद है कि हर कुछ घंटों में केवल एक ही होगा। वर्तमान में वे प्रति मिनट कई बार पॉप अप करते हैं।

इसके अलावा, मुझे trancount = 2 पर कुछ और जानकारी मिली है, जो नेस्टेड लेनदेन के साथ एक समस्या का संकेत हो सकता है, जिसे हम वास्तव में उपयोग कर रहे हैं। मैं यहां भी परिणामों की जांच करूंगा।


2
SELECT * का प्रयोग न करें। यह आपकी समस्याओं में एक योगदान कारक हो सकता है। देखें stackoverflow.com/questions/3639861/…
JamieSee

इसके अलावा, SELECT OBJECT_NAME(objectid, dbid) AS objectname, * FROM sys.dm_exec_sql_text(0x0200000024a9e43033ef90bb631938f939038627209baafb0000000000000000000000000000000000000000)वास्तव में निष्पादित किया जा रहा है या नहीं यह निर्धारित करने के लिए प्रत्येक एक्स्टेंकस्टैक फ्रेम पर sqlhandle के लिए चलाएं।
JamieSee

क्या आप हैश टक्कर में भाग रहे हैं, शायद? dba.stackexchange.com/questions/80088/insert-only-deadlocks/…
Johnboy

हे लोग, मुझे डर है कि मैं अब इस परियोजना का हिस्सा नहीं हूं: - /, इसलिए मैं आपके सुझावों की कोशिश नहीं कर सकता। हालाँकि, मैंने कुछ टीम के सदस्यों को थ्रेड और सारी जानकारी अग्रेषित कर दी है ताकि वे इसे मेरे स्थान पर देख सकें।
बेन

आप इस प्रश्न का उत्तर देने के लिए मेरे PowerShell स्क्रिप्ट का उपयोग कर सकते हैं और अधिक गतिरोध विवरण प्राप्त कर सकते हैं जो आपकी सहायता कर सकते हैं। विशेष रूप से, यह आपके "अज्ञात" स्टैक फ़्रेम के लिए SQL कथन जानकारी प्राप्त करेगा। dba.stackexchange.com/questions/28996/…
JamieSee

जवाबों:


2

मैंने इस आशय से कुछ टिप्पणी की है, लेकिन मुझे यकीन नहीं है कि जब आप रिपीटेबल रीडिंग आइसोलेशन लेवल को कमिटेड स्नैपशॉट के साथ जोड़ते हैं तो आपको वांछित परिणाम प्राप्त होते हैं।

आपकी गतिरोध सूची में दर्ज की गई टीआईएल दोहराए जाने योग्य है, जो रीड कमिटेड की तुलना में और भी अधिक प्रतिबंधात्मक है, और आपके द्वारा वर्णित प्रवाह को गतिरोध की ओर अग्रसर करता है।

आप जो करने की कोशिश कर रहे हैं वह यह है कि आपके DB TIL को बार-बार पढ़ा जा सकता है, लेकिन स्नैपशॉट TIL का उपयोग करने के लिए लेन-देन को स्पष्ट रूप से एक सेट लेनदेन अलगाव स्तर विवरण के साथ सेट करें। संदर्भ: https://msdn.microsoft.com/en-us/library/ms173763.aspx यदि ऐसा है, तो मुझे लगता है कि आपके पास कुछ गलत होना चाहिए। मैं nHibernate से परिचित नहीं हूँ, लेकिन ऐसा लगता है कि यहाँ एक संदर्भ है: http://www.anujvarma.com/fluent-nhibernate-setting-database-transaction-isolation-level/

यदि आपके ऐप का आर्किटेक्चर इसकी अनुमति देगा, तो एक विकल्प यह होगा कि db स्तर पर प्रतिबद्ध स्नैपशॉट पढ़ने की कोशिश करें, और यदि आप अभी भी डेडलॉक प्राप्त करते हैं, तो स्नैपशॉट को पंक्ति संस्करण के साथ सक्षम करें। ध्यान दें, यदि आप ऐसा करते हैं, तो आपको स्नैपशॉट (पंक्ति संस्करण) को सक्षम करने पर अपने अस्थायी सेटअप पर फिर से विचार करने की आवश्यकता है। अगर आपको इसकी आवश्यकता है तो मैं आपको सभी प्रकार की सामग्री प्राप्त कर सकता हूं - मुझे बताएं।


2

मेरे कुछ विचार हैं। सबसे पहले, गतिरोध से बचने का सबसे आसान तरीका है कि हमेशा एक ही क्रम में ताले लें। इसका मतलब है कि स्पष्ट लेनदेन का उपयोग करने वाले विभिन्न कोड को उसी क्रम में वस्तुओं का उपयोग करना चाहिए, लेकिन एक स्पष्ट लेनदेन में कुंजी द्वारा व्यक्तिगत रूप से पंक्तियों को एक्सेस करना चाहिए। Visit.VisitItemsऐसा करने से पहले Addया Deleteजब तक इस मामले में मैं उस पर एक बड़ा संग्रह नहीं होता, तब तक इसके पीके द्वारा छाँटने की कोशिश करें SELECT

छँटाई शायद आपकी समस्या यहाँ नहीं है। मैं अनुमान लगा रहा हूँ कि 2 धागे VisitItemIDकिसी दिए गए VisitIDऔर थ्रेड ए के लिए साझा किए गए ताले को साझा DELETEनहीं कर सकते हैं, जब तक कि थ्रेड बी अपने साझा लॉक को तब तक DELETEपूरा नहीं करता जब तक कि यह पूरा नहीं हो जाता। ऐप लॉक यहां काम करेंगे और टेबल लॉक की तरह खराब नहीं होंगे क्योंकि वे केवल विधि द्वारा ब्लॉक SELECTकरते हैं और अन्य एस ठीक काम करेंगे। आप Visitदिए गए VisitIDलेकिन फिर से टेबल पर एक विशेष ताला लगा सकते हैं, यह संभावित ओवरकिल है।

मैं आपकी हार्ड डिलीट को एक सॉफ्ट डिलीट ( UPDATE ... SET IsDeleted = 1यूज़ करने के बजाय DELETE) में बदलने की सलाह दूंगा और बाद में इन रिकॉर्ड्स को साफ़ करके, बल्क में, कुछ क्लीनअप जॉब का उपयोग करके, जो स्पष्ट ट्रांजेक्शन का उपयोग नहीं करता। यह स्पष्ट रूप से इन हटाए गए पंक्तियों को अनदेखा करने के लिए अन्य कोड को फिर से भरने की आवश्यकता होगी, लेकिन एक स्पष्ट लेनदेन में DELETEशामिल एस को संभालने के लिए मेरी पसंदीदा विधि है SELECT

आप SELECTलेन-देन से भी हटा सकते हैं और एक आशावादी संगामिति मॉडल पर स्विच कर सकते हैं। एंटिटी फ्रेमवर्क मुफ्त में ऐसा करता है, NHibernate के बारे में निश्चित नहीं है। यदि आपकी DELETEरिटर्न 0 पंक्तियाँ प्रभावित होती हैं, तो EF एक आशावादी संक्षिप्तता अपवाद को बढ़ाएगा ।


1

क्या आपने किसी भी संशोधन से पहले विज़िट अपडेट को स्थानांतरित करने की कोशिश की है? उस एक्स-लॉक को "बच्चे" पंक्तियों की रक्षा करनी चाहिए।

पूर्ण ताले को अधिग्रहित ट्रेस (और मानव-पठनीय में रूपांतरण) करना बहुत काम है, लेकिन अनुक्रम को अधिक स्पष्ट रूप से दिखा सकता है।


-1

यदि आपके पास कोई सुराग नहीं है कि एक टेबल क्यों अटक रही है, तो कभी-कभी एक ट्रैप अटक जाता है

XACT_ABORT को सेट करें -> इसमें त्रुटियों का ध्यान रखा जाना चाहिए, जिससे ट्रे को BEGIN TRAN TRAN_NAME से रोका जा सके - तालिका को एक्सेस करना - COMMIT TRAN TRAN_NAME

https://stackoverflow.com/questions/2277254/how-to-set-xact-abort-within-ado-net


-1

READ COMMITTED SNAPSHOT ON का मतलब है कि READ COMMITTED ISOLATION LEVEL में चलने वाला हर एक ट्रांजैक्शन READ COMMITTED SNAPSHOT की तरह काम करेगा।

इसका मतलब यह है कि पाठक लेखकों को ब्लॉक नहीं करेंगे और लेखक पाठकों को ब्लॉक नहीं करेंगे।

आप बार-बार पढ़ने वाले लेन-देन अलगाव स्तर का उपयोग करते हैं, यही कारण है कि आपके पास गतिरोध है। पढ़ें (बिना स्नैपशॉट के) कथन के अंत तक पंक्तियों / पृष्ठों पर ताले लगे रहते हैं , लेकिन दोहराने योग्य लेन-देन के अंत तक ताले पढ़ें ।

यदि आप अपने डेडलॉक ग्राफ पर एक नज़र डालते हैं, तो आप "S" लॉक का अधिग्रहण कर सकते हैं। मुझे लगता है कि यह दूसरे बिंदु से लॉक है -> "विजिटआई द्वारा दी गई यात्रा के लिए सभी विज़िट आइटम पढ़ें।"

  1. पढ़ने के लिए अपने NHibernate कनेक्शन लेन-देन अलगाव स्तर को बदलें
  2. आपको अपने 2 अंक के लिए क्वेरी का विश्लेषण करने और यह समझने की आवश्यकता है कि पीके पर ताले क्यों प्राप्त होते हैं यदि आपके पास आपके विज़िटआईडी कॉलम पर एक इंडेक्स है (यह आपके इंडेक्स में लापता कॉलम शामिल होने के कारण हो सकता है)।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.