Frage

alt text

Hier ist das Szenario:

Ich habe eine Tabelle namens MarketDataCurrent (MDC), die Live-Aktualisierung Aktienkurse hat.

Ich habe ein Prozess namens ‚Livefeed‘ bekam die Preise Streaming aus dem Draht, Warteschlangen Einsätze liest und verwendet eine ‚Bulk-Upload auf temporäre Tabelle dann insert / update auf MDC-Tabelle.‘ (BulkUpsert)

Ich habe einen anderen Prozess bekam, die dann diese Daten liest, berechnet andere Daten und speichert dann die Ergebnisse in der gleichen Tabelle zurück, eine ähnliche BulkUpsert gespeicherte Prozedur verwendet wird.

Drittens gibt es eine Vielzahl von Benutzern C # Gui Abfrage der MDC-Tabelle ausgeführt wird und das Lesen Updates von ihm.

Jetzt während des Tages, wenn die Daten schnell ändern, die Dinge laufen ziemlich glatt, aber dann, nach Markt Stunden, haben wir eine zunehmende Anzahl von Deadlock Ausnahmen sehen kommt aus der Datenbank vor kurzem damit begonnen, heute sehen wir 10- 20 pro Tag. Der imporant, was hier zu beachten ist, dass diese passieren, wenn die Werte nicht ändern.

Hier alle relevanten Informationen:

Tabelle Def:

CREATE TABLE [dbo].[MarketDataCurrent](
 [MDID] [int] NOT NULL,
 [LastUpdate] [datetime] NOT NULL,
 [Value] [float] NOT NULL,
 [Source] [varchar](20) NULL, 
CONSTRAINT [PK_MarketDataCurrent] PRIMARY KEY CLUSTERED 
(
 [MDID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, 
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

-

alt text

Ich habe ein SQL Profiler Trace bekam Rennen, die Deadlocks zu kontrollieren, und hier ist, was alle Graphen aussehen.

alt text

Prozess 258 wird folgende ‚BulkUpsert‘ gespeicherte Prozedur, wiederholt aufgerufen, während 73 die nächsten Aufruf:

ALTER proc [dbo].[MarketDataCurrent_BulkUpload]
 @updateTime datetime,
 @source varchar(10)
as

begin transaction

update c with (rowlock) set LastUpdate = getdate(), Value = t.Value, Source = @source 
from MarketDataCurrent c INNER JOIN #MDTUP t ON c.MDID = t.mdid
where c.lastUpdate < @updateTime
and   c.mdid not in (select mdid from MarketData where LiveFeedTicker is not null     and     PriceSource like 'LiveFeed.%')
and   c.value <> t.value

insert  into MarketDataCurrent
with (rowlock)
select  MDID, getdate(), Value, @source from #MDTUP 
where mdid not in (select mdid from MarketDataCurrent with (nolock))
and  mdid not in (select mdid from MarketData where LiveFeedTicker is not null     and PriceSource like 'LiveFeed.%')

commit

Und der andere:

ALTER PROCEDURE [dbo].[MarketDataCurrent_LiveFeedUpload] 
AS
begin transaction

 -- Update existing mdid
 UPDATE c WITH (ROWLOCK) SET LastUpdate = t.LastUpdate, Value = t.Value, Source = t.Source 
 FROM MarketDataCurrent c INNER JOIN #TEMPTABLE2 t ON c.MDID = t.mdid;

 -- Insert new MDID
 INSERT INTO MarketDataCurrent with (ROWLOCK) SELECT * FROM #TEMPTABLE2 
 WHERE MDID NOT IN (SELECT MDID FROM MarketDataCurrent with (NOLOCK))

 -- Clean up the temp table
 DELETE #TEMPTABLE2

commit

Um zu klären, werden diese Temp Tabellen durch den C # -Code auf derselben Verbindung erstellt werden und werden mit der C # SqlBulkCopy Klasse bevölkern.

Für mich sieht es aus wie es auf der PK der Tabelle Deadlocks, also habe ich versucht zu entfernen, dass PK und stattdessen auf einen eindeutigen Constraint Schalt aber das erhöht die Anzahl der Deadlocks 10-fach.

bin ich völlig verloren, was über diese Situation zu tun und sind offen zu fast jeden Vorschlag.

HELP !!


Als Antwort auf die Anfrage für den XDL, hier ist es:

<deadlock-list>
 <deadlock victim="processc19978">
  <process-list>
   <process id="processaf0b68" taskpriority="0" logused="0" waitresource="KEY: 6:72057594090487808 (d900ed5a6cc6)" waittime="718" ownerId="1102128174" transactionname="user_transaction" lasttranstarted="2010-06-11T16:30:44.750" XDES="0xffffffff817f9a40" lockMode="U" schedulerid="3" kpid="8228" status="suspended" spid="73" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2010-06-11T16:30:44.750" lastbatchcompleted="2010-06-11T16:30:44.750" clientapp=".Net SqlClient Data Provider" hostname="RISKAPPS_VM" hostpid="3836" loginname="RiskOpt" isolationlevel="read committed (2)" xactid="1102128174" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="MKP_RISKDB.dbo.MarketDataCurrent_BulkUpload" line="28" stmtstart="1062" stmtend="1720" sqlhandle="0x03000600a28e5e4ef4fd8e00849d00000100000000000000">
UPDATE c WITH (ROWLOCK) SET LastUpdate = getdate(), Value = t.Value, Source = @source 
FROM MarketDataCurrent c INNER JOIN #MDTUP t ON c.MDID = t.mdid
WHERE c.lastUpdate &lt; @updateTime
and   c.mdid not in (select mdid from MarketData where BloombergTicker is not null and PriceSource like &apos;Blbg.%&apos;)
and   c.value &lt;&gt; t.value     </frame>
     <frame procname="adhoc" line="1" stmtstart="88" sqlhandle="0x01000600c1653d0598706ca7000000000000000000000000">
exec MarketDataCurrent_BulkUpload @clearBefore, @source     </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
(@clearBefore datetime,@source nvarchar(10))exec MarketDataCurrent_BulkUpload @clearBefore, @source    </inputbuf>
   </process>
   <process id="processc19978" taskpriority="0" logused="0" waitresource="KEY: 6:72057594090487808 (74008e31572b)" waittime="718" ownerId="1102128228" transactionname="user_transaction" lasttranstarted="2010-06-11T16:30:44.780" XDES="0x380be9d8" lockMode="U" schedulerid="5" kpid="8464" status="suspended" spid="248" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2010-06-11T16:30:44.780" lastbatchcompleted="2010-06-11T16:30:44.780" clientapp=".Net SqlClient Data Provider" hostname="RISKBBG_VM" hostpid="4480" loginname="RiskOpt" isolationlevel="read committed (2)" xactid="1102128228" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="MKP_RISKDB.dbo.MarketDataCurrentBlbgRtUpload" line="14" stmtstart="840" stmtend="1220" sqlhandle="0x03000600005f9d24c8878f00849d00000100000000000000">
UPDATE c WITH (ROWLOCK) SET LastUpdate = t.LastUpdate, Value = t.Value, Source = t.Source 
        FROM MarketDataCurrent c INNER JOIN #TEMPTABLE2 t ON c.MDID = t.mdid;

        -- Insert new MDID     </frame>
     <frame procname="adhoc" line="1" sqlhandle="0x010006004a58132228bf8d73000000000000000000000000">
MarketDataCurrentBlbgRtUpload     </frame>
    </executionStack>
    <inputbuf>
MarketDataCurrentBlbgRtUpload    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <keylock hobtid="72057594090487808" dbid="6" objectname="MKP_RISKDB.dbo.MarketDataCurrent" indexname="PK_MarketDataCurrent" id="lock5ba77b00" mode="U" associatedObjectId="72057594090487808">
    <owner-list>
     <owner id="processc19978" mode="U"/>
    </owner-list>
    <waiter-list>
     <waiter id="processaf0b68" mode="U" requestType="wait"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057594090487808" dbid="6" objectname="MKP_RISKDB.dbo.MarketDataCurrent" indexname="PK_MarketDataCurrent" id="lock65dca340" mode="U" associatedObjectId="72057594090487808">
    <owner-list>
     <owner id="processaf0b68" mode="U"/>
    </owner-list>
    <waiter-list>
     <waiter id="processc19978" mode="U" requestType="wait"/>
    </waiter-list>
   </keylock>
  </resource-list>
 </deadlock>
</deadlock-list>
War es hilfreich?

Lösung 4

Ich habe dieses Problem endlich gelöst, nach fast zwei Jahren von lästigen Deadlock Warnung E-Mail.

Ich beschloß es von FULL TABLE SPERREN auf meine konkurrierenden Einsätze verwenden. Ich hatte Verriegelungs versucht Reduktionsstufe zu bringen, aber die Schleusen Tabellenebene wurden eskaliert. Am Ende habe ich beschlossen, der Tisch klein genug war, dass, obwohl viele Benutzer lesen und jede Sekunde, um es zu schreiben, dass eine vollständige Sperre eine kleine Leistung war traf ich war bereit für die Datenkonsistenz zu nehmen.

Darüber hinaus kombiniert die insert / update auf eine atomare Anweisung MERGE mit mir erlaubt, dies zu tun.

Hier ist der aufgelöste Produktionscode (es funktioniert!):

declare @date datetime;
set @date = getdate();

merge marketdatacurrent with (tablockx) as mdc

using #MDTUP as upload
    on mdc.MDID = upload.MDID

when matched then
    update
    set mdc.lastupdate = @date,
        mdc.value = upload.value,
        mdc.source = @source

when not matched then
    insert ( mdid, lastupdate, value, source )
    values ( upload.mdid, @date, upload.value, @source);

Andere Tipps

Die Blockade scheint auf Schlüsselzugang geradeaus Deadlocks zu sein. Eine triviale Erklärung ist Überlappung der aktualisierten Schlüssel zwischen den beiden Bulk-Update-Operationen.

Eine weniger trivial Erklärung ist aber, dass in SQL Server (und anderen Servern auch) die gesperrten Tasten gehashten , und es gibt eine (ziemlich signifikant) Hash-Kollisionswahrscheinlichkeit. Dies würde erklären, warum Sie mehr Deadlocks sehen in letzter Zeit im Vergleich zu vor: einfach Ihre Datenvolumen haben zugenommen und hat daher die Kollisionswahrscheinlichkeit erhöht. Wenn diese esoterischen und unwahrscheinlich scheint, lesen Sie einfach auf unter %% lockres %% Kollisionswahrscheinlichkeit magic Marker: 16.777.215 , und der Artikel aus, dass verknüpft. Die Wahrscheinlichkeit ist überraschend hoch, für eine perfekt Schlüsselverteilung Sie 50% Kollisionswahrscheinlichkeit hat erst nach ~ 16M-Einsätzen. Für normale, reale Welt, Schlüsselverteilungen haben Sie erhebliche Kollisionswahrscheinlichkeit bei nur wenigen tausend Einsätze. Leider gibt es keine Arbeit um. Ihre einzige Lösung, wenn dies wirklich das Problem ist, ist die Größe der Chargen (die Größe der #temp Tabellen) zu reduzieren, so dass die Kollisionswahrscheinlichkeit verringert. Oder handeln von Deadlocks und Wiederholungs ... die Sie ohnehin tun müssen werden, aber zumindest können Sie befassen sich mit weniger Deadlocks.

Es passiert nach den Hauptgeschäftszeiten, werden die Daten nicht verändert und es vor kurzem begonnen. Hat sich etwas vor kurzem auf dem Server ändern? Ich würde einige neue Datenbankwartung Job vermuten könnte stören.

BTW, wenn Sie wissen, dass der Markt geschlossen ist und die Daten nicht ändern, warum ist Ihr Prozess läuft noch?

Ich möchte eine Frage beantworten, ich in einem Kommentar gefragt, was ist,

„Wie erkennen Sie die Zeilen, die Sperren sind?“.

In der folgenden Deadlock XDL, auf den beiden „Prozess“ Knoten, die Verriegelungs sind, gibt es eine waitresource Attribut. in diesem Fall:

waitresource="KEY: 6:72057594090487808 (d4005c04b35f)

und

waitresource="KEY: 6:72057594090487808 (b00072ea4ffd)

Mit dem %%lockres%% Stichwort Remus zeigte auf,

select %%lockres%%, * from MarketDataCurrent 
   where %%lockres%% in ('(d4005c04b35f)', '(b00072ea4ffd)')

Damit werden die beiden Reihen geführt, die in Konflikt stehen. sie sind in der Tat einzigartig ids, und es gibt keine Kollision. Ich weiß immer noch nicht, warum ich ein Deadlock hier bekommen, aber ich bin immer näher.

Ich werde beachten Sie, dass beide der ids sollen, nur aus dem Livefeed-Programm kommen, aber auch hier gibt es eine Klausel in dem Update, das sollte diese Zeile zu Ausfiltern von tatsächlich von der anderen Seite zu aktualisieren.

<deadlock-list>
 <deadlock victim="processffffffff8f5872e8">
  <process-list>
   <process id="process8dcb68" taskpriority="0" logused="1256" waitresource="KEY: 6:72057594090487808 (d4005c04b35f)" waittime="1906" ownerId="1349627324" transactionname="user_transaction" lasttranstarted="2010-06-16T16:50:04.727" XDES="0x424e6258" lockMode="U" schedulerid="2" kpid="1004" status="suspended" spid="683" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2010-06-16T16:50:04.727" lastbatchcompleted="2010-06-16T16:50:04.727" clientapp=".Net SqlClient Data Provider" hostname="RISKAPPS_VM" hostpid="2600" loginname="RiskOpt" isolationlevel="read committed (2)" xactid="1349627324" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="MKP_RISKDB.dbo.MarketDataCurrent_BulkUpload" line="28" stmtstart="1062" stmtend="1720" sqlhandle="0x03000600a28e5e4ef4fd8e00849d00000100000000000000">
        UPDATE c WITH (ROWLOCK) SET LastUpdate = getdate(), Value = t.Value, Source = @source 
        FROM MarketDataCurrent c INNER JOIN #MDTUP t ON c.MDID = t.mdid
        WHERE c.lastUpdate &lt; @updateTime
        and   c.mdid not in (select mdid from MarketData where BloombergTicker is not null and PriceSource like &apos;Blbg.%&apos;)
        and   c.value &lt;&gt; t.value     </frame>
             <frame procname="adhoc" line="1" stmtstart="88" sqlhandle="0x01000600c1653d0598706ca7000000000000000000000000">
        exec MarketDataCurrent_BulkUpload @clearBefore, @source     </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">unknown</frame>
    </executionStack>
    <inputbuf>(@clearBefore datetime,@source nvarchar(10))exec MarketDataCurrent_BulkUpload @clearBefore, @source</inputbuf>
   </process>
   <process id="processffffffff8f5872e8" taskpriority="0" logused="0" waitresource="KEY: 6:72057594090487808 (b00072ea4ffd)" waittime="1921" ownerId="1349627388" transactionname="user_transaction" lasttranstarted="2010-06-16T16:50:04.757" XDES="0x289ea040" lockMode="U" schedulerid="5" kpid="11192" status="suspended" spid="382" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2010-06-16T16:50:04.757" lastbatchcompleted="2010-06-16T16:50:04.757" clientapp=".Net SqlClient Data Provider" hostname="RISKBBG_VM" hostpid="2452" loginname="RiskOpt" isolationlevel="read committed (2)" xactid="1349627388" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="MKP_RISKDB.dbo.MarketDataCurrentBlbgRtUpload" line="14" stmtstart="840" stmtend="1220" sqlhandle="0x03000600005f9d24c8878f00849d00000100000000000000">
        UPDATE c WITH (ROWLOCK) SET LastUpdate = t.LastUpdate, Value = t.Value, Source = t.Source 
        FROM MarketDataCurrent c INNER JOIN #TEMPTABLE2 t ON c.MDID = t.mdid;
    </frame>
     <frame procname="adhoc" line="1" sqlhandle="0x010006004a58132228bf8d73000000000000000000000000">
        MarketDataCurrentBlbgRtUpload     </frame>
    </executionStack>
    <inputbuf>
        MarketDataCurrentBlbgRtUpload    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <keylock hobtid="72057594090487808" dbid="6" objectname="MKP_RISKDB.dbo.MarketDataCurrent" indexname="PK_MarketDataCurrent" id="lock409d32c0" mode="U" associatedObjectId="72057594090487808">
    <owner-list>
     <owner id="processffffffff8f5872e8" mode="U"/>
    </owner-list>
    <waiter-list>
     <waiter id="process8dcb68" mode="U" requestType="wait"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057594090487808" dbid="6" objectname="MKP_RISKDB.dbo.MarketDataCurrent" indexname="PK_MarketDataCurrent" id="lock706647c0" mode="U" associatedObjectId="72057594090487808">
    <owner-list>
     <owner id="process8dcb68" mode="U"/>
    </owner-list>
    <waiter-list>
     <waiter id="processffffffff8f5872e8" mode="U" requestType="wait"/>
    </waiter-list>
   </keylock>
  </resource-list>
 </deadlock>
</deadlock-list>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top