Si un punto muerto de evento de intercambio de paralelismo no tiene víctimas, ¿es un problema?

10

Estamos viendo muchos de estos interbloqueos de subprocesos paralelos de consulta en nuestro entorno de producción (SQL Server 2012 SP2 - sí ... lo sé ...), sin embargo, al mirar el XML de Deadlock que se ha capturado a través de eventos extendidos, La lista de víctimas está vacía.

<victim-list />

El punto muerto parece estar entre 4 hilos, dos con el WaitType="e_waitPipeNewRow"y dos con el 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>

Entonces:

  1. La lista de víctimas está vacía
  2. La aplicación que ejecuta la consulta no produce errores y completa la consulta.
  3. Hasta donde podemos ver, no hay un problema obvio, aparte de eso, se captura el gráfico

Por lo tanto, ¿hay algo de qué preocuparse aparte del ruido?

Editar: Gracias a la respuesta de Paul, puedo ver dónde ocurre el problema y parece resolverse con el derrame de tempdb. ingrese la descripción de la imagen aquí

Mark Sinkinson
fuente

Respuestas:

11

No me sorprendería si esta es la forma en que se ve el gráfico de punto muerto cuando se resuelve un punto muerto paralelo dentro de una consulta mediante un derrame de intercambio (por lo que no hay víctimas, excepto el rendimiento).

Puede confirmar esta teoría capturando derrames de intercambio y emparejándolos (o no) con el punto muerto.

Escribir buffers de intercambio en tempdb para resolver un punto muerto no es ideal. Busque eliminar secuencias de operaciones de preservación de órdenes en el plan de ejecución (por ejemplo, intercambios de preservación de órdenes que alimentan una combinación de fusión paralela). A menos que no esté causando un problema de rendimiento notable, y tenga otras cosas de qué preocuparse.

Por interés, ¿es probable que este problema se vea exacerbado por estadísticas de alta fragmentación / desactualizadas?

Fragmentación, no. Estadísticas desactualizadas: no puedo pensar en ningún sentido específico, no. Por supuesto, las estadísticas no representativas rara vez son algo bueno en general.

El problema fundamental aquí es que el paralelismo funciona mejor cuando hay la menor cantidad posible de dependencias entre los hilos; el orden conservado introduce dependencias bastante desagradables. Las cosas pueden complicarse fácilmente, y la única forma de despejar el logjam es derramar un montón de filas en los intercambios a tempdb .

Paul White 9
fuente
-1

Para distinguir estos puntos muertos no críticos, de "auto resolución por derrame" de los puntos muertos más importantes, se puede aplicar una semántica de búsqueda a la estructura Xdl.

Salida de ejemplo

El siguiente SP no funcionará de fábrica, ya que depende de ufn_ExtractSubstringsByPattern (), sin embargo, ese método se puede reemplazar con algo que devuelva el recuento distintivo directamente.

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
fuente