6
votes

Deadlock dans SQL Server 2005! Deux bouleversards en vrac en temps réel se battent. POURQUOI?

text alt

Voici le scénario: P>

J'ai Vous avez une table appelée MarketDatacurrent (MDC) qui a mis à jour les cours des actions. P>

J'ai un processus appelé «LiveFeed» qui lit les prix diffusés en streaming sur le fil, files d'attente des inserts et utilise un «téléchargement en vrac vers TIMP puis insertion / mise à jour sur la table MDC. ' (BulkuSert) p>

J'ai un autre processus qui lit ensuite ces données, calcule d'autres données, puis enregistre les résultats dans la même table, à l'aide d'un PROP SIMLOI BULKUPSERT STORED. P>

Troisièmement, il existe une multitude d'utilisateurs qui exécutent une graphique C # interrompant la table MDC et lisent des mises à jour de celle-ci. P>

Maintenant, pendant la journée où les données changent rapidement, les choses fonctionnent assez bien, mais ensuite, Après des heures de marché, nous avons récemment commencé à voir un nombre croissant d'exceptions d'impasse sortant de la base de données, nous voyons aujourd'hui 10-20 par jour. La chose imporchante à noter ici est que celles-ci se produisent lorsque les valeurs ne changent pas. P>

Voici toutes les informations pertinentes: p>

Table def: P>

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


5 commentaires

Que se passe-t-il si vous supprimez les spécificateurs Explicites Rowlock et Nolock? Sont l'une des sources de données mentionnées dans la vue de vos requêtes plutôt que dans les tables, et si vous pourriez le faire, veuillez poster la source de vue? Merci.


Aucune des sources de données n'est des vues. En réalité, l'ajout du Rowlock explicite et Nolock a contribué à réduire le nombre de blocages.


Mieux vaut poster l'impasse XDL, pas l'image. Les images peuvent être décomposées ... rusanu.com/2010/05/12/Le-puzzzle-of-u-locks-in-deadlock-grap hs


C'était un article intéressant en effet, et maintenant j'ai quelque chose de plus à rechercher, mais comme vous pouvez le voir de ce XDL, ils semblent tous être des serrures. Je vais regarder à travers un peu de plus et voir si je peux en trouver un qui n'est pas.


+1 juste pour la qualité de la question de la question, si rien d'autre


4 Réponses :


1
votes

Cela se produit après les principales heures de bureau, les données ne changent pas et cela vient de commencer récemment. Est-ce que quelque chose a récemment changé sur le serveur? Je soupçonnerais un nouveau travail de maintenance de la base de données pourrait interférer.

BTW Si vous savez que le marché est fermé et que les données ne changent pas, pourquoi votre processus est-il toujours en cours d'exécution?


2 commentaires

Je gère le serveur et connais tout ce qui fonctionne dessus. Il y a un travail de sauvegarde SQL DTSS qui fait une sauvegarde complète toutes les nuits au même disque dur physique, puis une autre DTSS sur un autre serveur SQL qui copie du lecteur local de mon serveur à un réseau 'Snap Server'


Je suis trop simplifiant les données qui ne mettent pas à jour du tout. La plupart des marchés sont fermés, mais le FX est effectivement ouvert 24/5 afin de pouvoir traiter ce marché.



2
votes

L'impasse semble être des blocages directs directement sur l'ordre d'accès clé. Une explication triviale se chevauche des clés mises à jour entre les deux opérations de mise à jour en vrac.

Une explication moins triviale Bien que c'est que, dans SQL Server (et d'autres serveurs), les touches verrouillées sont hachées , et il existe une probabilité de collision de hachage (assez importante). Cela expliquerait pourquoi vous voyez plus de blocages ces derniers temps comparés avant: simplement votre volume de données a augmenté et donc la probabilité de collision a augmenté. Si cela semble ésotérique et improbable, il suffit de lire sur %% Lockres %% Probabilité de collision Marqueur magique: 16 777.215 , et l'article relié de cela. La probabilité est étonnamment élevée, pour une parfaite répartition de la clé que vous avez une probabilité de collision de 50% après seulement ~ 16 m d'inserts. Pour la normale, le monde réel, des distributions clés que vous avez une probabilité de collision significative à seulement quelques milliers d'inserts. Malheureusement, il n'y a pas de travail autour. Votre seule solution, si c'est vraiment le problème, est de réduire la taille des lots (la taille des tables #TEpp) afin que la probabilité de collision soit réduite. Ou traiter avec des blocages et réessayer ... que vous devrez faire de toute façon, mais au moins vous pouvez faire face à moins impasse.


9 commentaires

Cette idée a été très utile jusqu'à présent. Je ne peux pas encore accepter de réponses jusqu'à ce que je monte avec un moyen de réduire ces blocages à un niveau acceptable, mais je pense que c'est sur la bonne voie. Votre article se lie à celui-ci, qui est très intéressant: consultingblogs.emc.com/jamesrowlandjones/archive/2009/05/28 / ... Il mentionne trois solutions possibles à Ce problème, dont n ° 1 est 1. Changez votre clé en une clé basée sur une intrigue, mais c'est exactement ce que j'ai. Le PK dans cette table est un Int unique, rien de plus


En fait, je suis en désaccord avec James sur celui-là. Modification de la clé en une clé de substitution INT fera exactement rien, les 8 octets int seront toujours hachés à la taille de la ressource de verrouillage, soit 6 octets. A mon humble avis. La seule approche raisonnable est de réduire les tailles de lots.


Il suffit de courir: Sélectionnez %% Lockres %% comme Lockhas, comptez () du groupe MarketDatacurrent par %% Lockres %% ayant compté ()> 1 (au milieu de la journée) et a obtenu 0 rangées! Notre table n'est pas réellement tout ce qui grand. ~ 32 000 rangées totales (c'est censé être très légère et ne disposer que de données en temps réel) ainsi, avec une ID INT unique, et des valeurs dans la gamme allant jusqu'à 250 000 collisions clés de hachage semblent presque impossibles comme une explication. Je vais courir cette requête à nouveau juste après la prochaine impasse pour voir s'il en existe à ce moment-là, mais je ne m'y attends pas.


De plus, FWIW, les tailles de lots sont d'environ 200 à 300 lignes sur un processus et 5000 pour l'autre.


Autre question, savez-vous comment je peux résoudre les identifiants réels des rangées qui sont une mauvaise manipulation de la XDL ci-dessus?


Avec de tels petits lots / tailles de table, il n'est pas très probable que la collision statistique (reste possible). Êtes-vous sûr que vos mises à jour ne se chevauchent pas? C'est à dire. Pas de collision de hasch, mais vraie collision clé.


ID = "LOCK65DCA340" : Pour trouver les lignes impressionnantes, vous exécutez SELECT * à partir de MKP_RISKDB.DBO.MarketDataCurrent où la soustrine (%% Lockres %%, 6,8) = '65DCA340' .


Étonnamment, cela n'a donné aucune lignée. J'ai vérifié la table principale (celle qui a la définition du MDID qui a les mêmes valeurs pour le PK et qu'elle n'a donné aucune ligne de lignes. J'ai également vérifié que les valeurs %% Lockres %% renvoie la correspondance de la clé à travers les deux tables . J'ai aussi vérifié qu'ils sont tout à fait uniques dans la table. Cela signifie qu'aucune collision de hachage. Damn! Ça me doit être des serrures de page, n'est-ce pas? Que se passe-t-il si je désactive les serrures de la page sur la table comme je l'ai suggéré ci-dessous?


J'ai fait de mon mieux pour vous assurer que les mises à jour ne se chevauchent pas en ajoutant et c.mdid non dans (Sélectionnez MDID à partir de MarketData où LiveFeedtTicker n'est pas nulle et des prix à la suite de "LiveFeed.%") à L'insert d'alimentation non en direct (qui ne fera que insérer des trucs dans cet ensemble). J'ai besoin de trouver les identifiants qui collants - mais que %% Lockres %% ne fonctionne pas. Le hash Algo pourrait-il changer dans le temps? De plus, les deux correspondants de Keylock ID conflinent-ils dans le XDL s'il y avait le même identifiant? La seule façon de voir une collision avec deux clés distinctes est si elles sont sur la même page ...



1
votes

J'aimerais répondre à une question que j'ai posée dans un commentaire, qui est

"Comment identifiez-vous les lignes qui sont verrouillantes?". P>

dans l'impasse XDL, ON Les deux nœuds "Processus" qui sont verrouillables, il y a un attribut WairsResource code>. Dans ce cas: p>

wairsource = "Key: 6: 72057594090487808 (D4005C04B35F) CODE> P>

et P>

wairsource =" Touche: 6: 72057594090487808 (B00072A4FFD) CODE> P>

Utilisation du %% Lockres %% Code> Mot-clé Remus pointé sur, P>

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


0 commentaires

0
votes

J'ai finalement résolu ce problème, après près de deux ans d'avertissements d'avertissement d'impasse gênant.

Je l'ai résolu en utilisant la table complète Verrouillage sur mes inserts concurrents. J'avais essayé de réduire le verrouillage au niveau de la rangée, mais les serrures escaladent au niveau de la table. En fin de compte, j'ai décidé que la table était assez petite que même si beaucoup d'utilisateurs y lisent et écrivent chaque seconde, qu'une serrure complète était une petite performance frappée, j'étais disposée à prendre pour la cohérence des données. < P> En outre, la combinaison de l'insertion / mise à jour à une instruction atomique utilisant Fusion me permet de le faire.

Voici le code de production résolu (cela fonctionne!): xxx


0 commentaires