Si un blocage d'événement d'échange de parallélisme est sans victime, est-ce un problème?

10

Nous voyons beaucoup de ces interblocages de threads parallèles intra-requête dans notre environnement de production (SQL Server 2012 SP2 - oui ... je sais ...), cependant quand on regarde le Deadlock XML qui a été capturé via des événements étendus, la liste des victimes est vide.

<victim-list />

Le blocage semble être entre 4 threads, deux avec le WaitType="e_waitPipeNewRow"et deux avec le WaitType="e_waitPipeGetRow".

 <resource-list>
  <exchangeEvent id="Pipe13904cb620" WaitType="e_waitPipeNewRow" nodeId="19">
   <owner-list>
    <owner id="process4649868" />
   </owner-list>
   <waiter-list>
    <waiter id="process40eb498" />
   </waiter-list>
  </exchangeEvent>
  <exchangeEvent id="Pipe30670d480" WaitType="e_waitPipeNewRow" nodeId="21">
   <owner-list>
    <owner id="process368ecf8" />
   </owner-list>
   <waiter-list>
    <waiter id="process46a0cf8" />
   </waiter-list>
  </exchangeEvent>
  <exchangeEvent id="Pipe13904cb4e0" WaitType="e_waitPipeGetRow" nodeId="19">
   <owner-list>
    <owner id="process40eb498" />
   </owner-list>
   <waiter-list>
    <waiter id="process368ecf8" />
   </waiter-list>
  </exchangeEvent>
  <exchangeEvent id="Pipe4a106e060" WaitType="e_waitPipeGetRow" nodeId="21">
   <owner-list>
    <owner id="process46a0cf8" />
   </owner-list>
   <waiter-list>
    <waiter id="process4649868" />
   </waiter-list>
  </exchangeEvent>
 </resource-list>

Donc:

  1. La liste des victimes est vide
  2. L'application exécutant la requête ne génère pas d'erreur et termine la requête
  3. Pour autant que nous puissions voir, il n'y a pas de problème évident, à part que le graphique est capturé

Par conséquent, est-ce quelque chose à craindre autre que le bruit?

Edit: Grâce à la réponse de Paul, je peux voir où le problème se produit probablement et semble se résoudre avec le déversement de tempdb. entrez la description de l'image ici

Mark Sinkinson
la source

Réponses:

11

Je ne serais pas surpris si c'est à quoi ressemble le graphique de blocage lorsqu'un blocage parallèle intra-requête est résolu par un déversement d'échange (il n'y a donc pas de victime, sauf les performances).

Vous pouvez confirmer cette théorie en capturant les déversements d'échange et en les faisant correspondre (ou non) à l'impasse.

L'écriture de tampons d'échange dans tempdb pour résoudre un blocage n'est pas idéale. Essayez d'éliminer les séquences d'opérations préservant l'ordre dans le plan d'exécution (par exemple, les échanges préservant l'ordre alimentant une jointure de fusion parallèle). À moins que cela ne cause pas un problème de performance notable et que vous ayez d'autres choses à vous soucier.

Par intérêt, ce problème est-il susceptible d'être exacerbé par une forte fragmentation / des statistiques obsolètes?

Fragmentation, non. Statistiques obsolètes: pas dans un sens précis auquel je pense, non. Bien sûr, les statistiques non représentatives sont rarement une bonne chose en général.

Le problème fondamental ici est que le parallélisme fonctionne mieux quand il y a aussi peu de dépendances entre les threads que possible; l'ordre ordonné introduit des dépendances plutôt désagréables. Les choses peuvent facilement être gommées, et la seule façon d'effacer le blocage est de renverser un tas de lignes tenues lors des échanges vers tempdb .

Paul White 9
la source
-1

Pour distinguer ces blocages non critiques "à résolution automatique par déversement" des blocages plus importants, une sémantique de recherche peut être appliquée à la structure Xdl.

Exemple de sortie

Le SP suivant ne fonctionnera pas hors de la boîte car il dépend de ufn_ExtractSubstringsByPattern () mais cette méthode peut être remplacée par quelque chose qui retourne directement le nombre distinct.

ALTER view [Common].[DeadLockRecentHistoryView]
as
/*---------------------------------------------------------------------------------------------------------------------
    Purpose:  List history of recent deadlock events

    Warning:  The XML processing may hit a recursion limit (100), suggest using "option (maxrecursion 10000)".

    Xdl File:
        The SSMS deadlock file format .XDL format (xml) has changed with later versions of SQL Server.  This version tested with 2012.

    Ring Buffer issues:
        https://connect.microsoft.com/SQLServer/feedback/details/754115/xevents-system-health-does-not-catch-all-deadlocks
        https://www.sqlskills.com/blogs/jonathan/why-i-hate-the-ring_buffer-target-in-extended-events/

    Links:
        http://www.sqlskills.com/blogs/jonathan/multi-victim-deadlocks/
        https://www.sqlskills.com/blogs/jonathan/graphically-viewing-extended-events-deadlock-graphs/
        http://www.mssqltips.com/sqlservertip/1234/capturing-sql-server-deadlock-information-in-xml-format/
        http://blogs.msdn.com/b/sqldatabasetalk/archive/2013/05/01/tracking-down-deadlocks-in-sql-database.aspx
        http://dba.stackexchange.com/questions/10644/deadlock-error-isnt-returning-the-deadlock-sql/10646#10646        

    Modified    By           Description
    ----------  -----------  ------------------------------------------------------------------------------------------
    2014.10.29  crokusek     From Internet, http://stackoverflow.com/questions/19817951
    2015.05.05  crokusek     Improve so that the output is consumable by SSMS 2012 as "Open .xdl file"                             
    2015.05.22  crokusek     Remove special character for the cast to Xml (like '&')
    2017.08.03  crokusek     Abandon ring-buffer approach and use event log files.  Filter out internal deadlocks.
    2018.07.16  crokusek     Added field(s) like ProbablyHandledBySpill to help identify non-critical deadlocks.
  ---------------------------------------------------------------------------------------------------------------------*/
with XmlDeadlockReports as
(
  select convert(xml, event_data) as EventData         
    from sys.fn_xe_file_target_read_file(N'system_health*.xel', NULL, NULL, NULL)      
   where substring(event_data, 1, 50) like '%"xml_deadlock_report"%'       
)
select top 10000
       EventData.value('(event/@timestamp)[1]', 'datetime2(7)') as CreatedUtc,
       --(select TimePst from Common.ufn_ConvertUtcToPst(EventData.value('(event/@timestamp)[1]', 'datetime2(7)'))) as CreatedPst,
       DistinctSpidCount,       
       HasExchangeEvent,
       IsVictimless,                  
       --
       -- If the deadlock contains Exchange Events and lists no victims, it probably occurred
       -- during execution of a single query that contained parallellism but got stuck due to 
       -- ordering issues.   /dba/197779
       -- 
       -- These will not raise an exception to the caller and will complete by spilling to tempdb
       -- however they may run much slower than they would without the spill(s).
       --
       convert(bit, iif(DistinctSpidCount = 1 and HasExchangeEvent = 1 and IsVictimless = 1, 1, 0)) as ProbablyHandledBySpill,
       len(et.XdlFileText) as LenXdlFile,
       eddl.XdlFile as XdlFile
  from XmlDeadlockReports
 cross apply 
     ( 
       select eventData.query('event/data/value/deadlock') as XdlFile 
     ) eddl
 cross apply 
     ( 
        select convert(nvarchar(max), eddl.XdlFile) as XdlFileText 
     ) as et
 cross apply 
     (
       select count(distinct Match) as DistinctSpidCount
         from common.ufn_ExtractSubstringsByPattern(et.XdlFileText, 'spid="%%"')
     ) spids
 cross apply
     (
       select convert(bit, iif(charindex('<exchangeEvent', et.XdlFileText) > 0, 1, 0)) as HasExchangeEvent,
              --
              convert(bit, iif(     charindex('<victim-list>', et.XdlFileText) = 0
                                and charindex('<victim-list/>', et.XdlFileText) > 0, 1, 0)) as IsVictimless
     ) as flags        
 order by CreatedUtc desc
GO
crokusek
la source