LATCH_EX espera en el recurso METADATA_SEQUENCE_GENERATOR

11

Tenemos un proceso que genera un informe de inventario. En el lado del cliente, el proceso se divide en un número configurable de subprocesos de trabajo para generar una porción de datos para el informe que corresponde a un almacén de muchos (potencialmente miles, generalmente docenas). Cada subproceso de trabajo llama a un servicio web que ejecuta un procedimiento almacenado.

El proceso de la base de datos para procesar cada fragmento reúne un conjunto de datos en una tabla #Temporary. Al final de cada fragmento de procesamiento, los datos se escriben en una tabla permanente en tempdb. Finalmente, al final del proceso, un hilo en el lado del cliente solicita todos los datos de la tabla temporal tempdb.

Cuantos más usuarios ejecuten este informe, más lento será. Analicé la actividad en la base de datos. En un momento, vi 35 solicitudes separadas, todas bloqueadas en un punto del proceso. Todos estos SPID tenían del orden de 50 ms esperas de tipo LATCH_EXen recurso METADATA_SEQUENCE_GENERATOR (00000010E13CA1A8). Un SPID tiene este recurso, y todos los demás están bloqueando. No encontré nada sobre este recurso de espera en una búsqueda web.

La tabla en tempdb que estamos usando tiene una IDENTITY(1,1)columna. ¿Están estos SPID esperando la columna IDENTIDAD? ¿Qué métodos podríamos usar para reducir o eliminar el bloqueo?

El servidor es parte de un clúster. El servidor ejecuta SQL Server 2012 Standard Edition SP1 de 64 bits en Windows 2008 R2 Enterprise de 64 bits. El servidor tiene 64 GB de RAM y 48 procesadores, pero la base de datos solo puede usar 16 porque es la edición estándar.

(Tenga en cuenta que no estoy entusiasmado con el diseño de usar una tabla permanente en tempdb para contener todos estos datos. Cambiar eso sería un desafío técnico y político interesante, pero estoy abierto a sugerencias).

ACTUALIZACIÓN 23/04/2013

Hemos abierto un caso de soporte con Microsoft. Mantendré esta pregunta actualizada a medida que aprendamos más.

ACTUALIZACIÓN 10/05/2013

El ingeniero de soporte de SQL Server acordó que las esperas fueron causadas por la columna IDENTIDAD. Eliminar la IDENTIDAD eliminó las esperas. No pudimos duplicar el problema en SQL 2008 R2; ocurrió solo en SQL 2012.

Paul Williams
fuente
¿El proceso esencialmente copia los datos de las tablas #Temporary a la tabla permanente, o hay una lógica de transformación adicional en ese paso?
Jon Seigel
En el paso que está esperando, está copiando los registros de inventario de una sola tienda en la tabla permanente sin transformación. Podríamos operar dentro de la tabla permanente todo el tiempo, pero creo que el programador optó por usar una tabla #Temporary como área de espera para evitar que las actualizaciones frecuentes de los datos se conviertan en bloqueos de PAGE.
Paul Williams

Respuestas:

4

Suponiendo que puede aislar el problema a la generación de valores de identidad (intente eliminar esa columna como prueba), lo que recomendaría es esto:

  1. Elimine la IDENTITYpropiedad de la columna en la tabla final.
  2. Genere valores de identidad en cada una de las tablas #Temporary.
  3. Al cargar la tabla final, combine un identificador numérico para la tienda en particular con los valores de identidad del paso 2.

Entonces, si tiene los identificadores de tienda 3 y 4, terminaría con valores de identificación finales como este:

3000000001
3000000002
3000000003
...
4000000001
4000000002
...

O algo similar a eso. Tienes la idea.

Esto eliminará la necesidad de serializar en la IDENTITYgeneración al tiempo que conserva la unicidad en el resultado final.

Alternativamente, dependiendo de cómo funcione el proceso, inserte los valores finales de identificación calculados en las tablas #Temporary. Luego, podría crear una vista que UNION ALLlos una a la vez, eliminando la necesidad de copiar los datos.

Jon Seigel
fuente
Gracias por la respuesta. Estoy de acuerdo si ese es el problema, el uso de alguna clave fabricada (o ninguna clave) podría solucionarlo. Hemos abierto un caso con Microsoft con respecto a este problema. Publicaré el resultado aquí y aceptaré su respuesta si están de acuerdo en que ese es el problema.
Paul Williams
@Paul: Por favor, házmelo saber; Tengo la misma curiosidad. Al igual que usted, no pude encontrar nada en la web sobre este cierre, pero ciertamente es razonable que sea la serialización de identidad / secuencia. Es difícil decir si ese es el cuello de botella o no, aunque con más de 30 hilos compitiendo por valores, parece probable. También puede intentar copiar de cada tabla #Temporary en serie (en lugar de en paralelo) para ver si eso ayuda.
Jon Seigel
2
El ingeniero de SQL Server estuvo de acuerdo en que probablemente era la IDENTITYcolumna. Lo quitamos del índice agrupado ya ancho y eliminamos la columna por completo. No era necesario. Después, estas esperas LATCH_EX desaparecieron. No pudimos duplicar las esperas en SQL 2008 R2. El problema ocurrió solo en SQL Server 2012.
Paul Williams
@Paul: Gracias por seguirnos. Muy interesante. Supongo que el código que genera IDENTITYvalores se reescribió para usar el nuevo material de generación de secuencias que era nuevo en 2012. En <2012, puede ver un tipo de bloqueo diferente, aunque si no hubo un problema de rendimiento, entonces parece que hubo Una regresión en el código. En cualquier caso, eliminar la IDENTITYcolumna es lo más seguro.
Jon Seigel
En lugar de identidad, podría intentar usar una 'SECUENCIA' (que es nueva en SQL 2012)
Bogdan Maxim
7

(Actualizado en febrero de 2019)

Esta es una publicación antigua, que decía que finalmente logré convencer a Microsoft de que el hecho de que esto ocurra es realmente un defecto.

Actualización: MS confirmó el defecto y le asignó un número de error # 12628722.

Había visto esta publicación el pasado noviembre de 2018 cuando comenzamos a sufrir lo mismo después de haber actualizado de Sql Server 2005 a Sql Server 2017. Una tabla de 3.3 millones de filas que solía tomar 10 segundos para la inserción masiva de repente comenzó a tomar 10 minutos en tablas con Identitycolumnas.

Resulta que hay dos problemas detrás de esto:

  1. Microsoft cambió el comportamiento en Sql Server 2014 para obligar a las inserciones masivas a ejecutarse en paralelo; en versiones anteriores, las inserciones masivas recibieron un plan serializado.
  2. Una vez que se ejecutó en paralelo en nuestra caja de 32 núcleos, el motor pasó más tiempo con los núcleos bloqueándose entre sí que realmente haciendo el trabajo.

Me tomó 4 semanas, pero justo después de las vacaciones recibí un regalo tardío de Santa, confirmación de que el problema era realmente un defecto.

Hay algunas soluciones posibles que encontramos hasta que se solucione esto:

  1. Úselo Option (MaxDop 1)en la consulta para convertir el inserto masivo nuevamente en un plan serializado.
  2. Enmascarar la columna de identidad lanzándola (p Select Cast(MyIdentityColumn As Integer) As MyIdentityColumn. Ej. )
    • esto evita que la propiedad de identidad se copie al usar SELECT...INTO
  3. Elimine la columna de identidad como se describe anteriormente.
  4. Cambie el modo de compatibilidad de la base de datos a Sql Server 2012 o inferior para restablecer un plan serializado.

Actualización: La solución que MS implementará será devolver este tipo de inserciones para volver a usar un Serialized plan. Esto está planeado para Sql Server 2017 CU14 (no hay noticias sobre otras versiones de Sql Server, ¡lo siento!). Cuando se implemente, será necesario activar Trace Flag 9492 , ya sea a nivel del servidor o mediante DBCC TraceOn .

Rachel Ambler
fuente