sql >> Base de Datos >  >> RDS >> Database

Estadísticas de espera instintivas:PAGELATCH

Durante los últimos 18 meses me he centrado en las reacciones instintivas al análisis de las estadísticas de espera y otros temas relacionados con el ajuste del rendimiento, y en esta publicación voy a continuar con eso y discutir el PAGELATCH_XX murga. El XX al final de la espera significa que hay varios tipos de PAGELATCH espera, y los ejemplos más comunes son:

  • PAGELATCH_SH – ( SH están) esperando el acceso a una página de archivo de datos en la memoria para que se pueda leer el contenido de la página
  • PAGELATCH_EX o PAGELATCH_UP – (EX exclusivo o UP date) esperando el acceso a una página de archivo de datos en la memoria para que el contenido de la página pueda modificarse

Cuando uno de estos tipos de espera es el más frecuente en un servidor, la reacción instintiva es que el problema tiene algo que ver con E/S (es decir, confusión con PAGEIOLATCH_XX tipo de espera, que cubrí en una publicación en 2014) y alguien intenta agregar más memoria o ajustar el subsistema de E/S. Ninguna de estas reacciones tendrá ningún efecto, ya que las páginas del archivo de datos en conflicto ya están en la memoria del grupo de búfer.

En todos los casos, puede ver si tiene un problema con PAGELATCH_XX contención mediante sys.dm_os_waiting_tasks script en mi blog o usando una herramienta como Performance Advisor, como se muestra (para un tipo de espera diferente) en esta publicación.

Entonces, ¿cuál es la fuente de la disputa? Primero, explicaré los antecedentes detrás de estos tipos de espera y, luego, analizaré las dos causas más comunes de PAGELATCH_XX contención.

Antecedentes:Pestillos

Antes de entrar en algunas de las causas de PAGELATCH_XX espera, quiero explicar por qué existen.

En cualquier sistema de subprocesos múltiples, las estructuras de datos a las que se puede acceder y manipular mediante subprocesos múltiples deben protegerse para evitar escenarios como:

  • Dos subprocesos que actualizan una estructura de datos al mismo tiempo y algunas de las actualizaciones se pierden
  • Un subproceso que actualiza una estructura de datos al mismo tiempo que otro subproceso lee la estructura de datos, por lo que el subproceso de lectura ve una mezcla de datos antiguos y nuevos

Esto es informática básica, y SQL Server no es diferente, por lo que todas las estructuras de datos dentro de SQL Server deben tener un control de acceso de subprocesos múltiples.

Uno de los mecanismos que usa SQL Server para hacer esto se llama pestillo, donde mantener el pestillo en modo exclusivo evita que otros subprocesos accedan a la estructura de datos, y mantener el pestillo en modo compartido evita que otros subprocesos cambien la estructura de datos. SQL Server también usa spinlocks para algunas estructuras de datos y los discutí en esta publicación en 2014.

Pero, ¿por qué una página de archivo de datos en la memoria está protegida por un pestillo? Bueno, una página de archivo de datos es solo una estructura de datos, aunque tiene un propósito especial, por lo que necesita los mismos controles de acceso que cualquier otra estructura de datos. Entonces, cuando un subproceso necesita modificar una página de archivo de datos, necesita adquirir un latch exclusivo o de actualización en la página, y si no puede y necesita esperar, el tipo de espera PAGELATCH_EX o PAGELATCH_UP resultados.

Contención clásica de tempdb

PAGELATCH la contención en tempdb suele estar en mapas de bits de asignación y ocurre con cargas de trabajo con muchas conexiones simultáneas que crean y eliminan pequeñas tablas temporales (que se almacenan en tempdb).

Cuando se inserta la primera fila en una tabla temporal, se deben asignar dos páginas (una página de datos y una página de IAM, que rastrea la página de datos). Estas páginas deben marcarse como asignadas en una página de asignación especial llamada página PFS y, de forma predeterminada, se asignan desde extensiones de datos especiales que son rastreadas por otra página de asignación llamada página SGAM (los detalles de estos se pueden encontrar en mi publicación de blog anterior aquí). Cuando se elimina la tabla temporal, estas páginas deben desasignarse nuevamente, lo que requiere más cambios en las páginas PFS y SGAM.

Si las tablas temporales son pequeñas y el tamaño acumulativo de todas las tablas temporales creadas simultáneamente es inferior a 64 MB, todos estos cambios en el mapa de bits de asignación se centran en las primeras páginas de PFS y SGAM en el archivo de datos tempdb (con ID de página (1:1) y (1:3) respectivamente). Actualizar una de estas páginas de asignación requiere bloquear la página, y solo un subproceso a la vez puede cambiar la página, por lo que todos los demás subprocesos deben esperar, con el tipo de espera PAGELATCH_UP .

Desde SQL Server 2005 en adelante, las tablas temporales se pueden almacenar en caché cuando se eliminan, siempre que tengan menos de 8 MB de tamaño (y en SQL Server 2014 no se crean en un procedimiento almacenado que también tiene instrucciones DDL en la tabla temporal). Esto significa que el siguiente subproceso que ejecuta el mismo plan de consulta puede sacar la tabla temporal de la memoria caché y no tener que ocuparse de las asignaciones iniciales. Esto reduce la contención en los mapas de bits de asignación, pero la memoria caché de la tabla temporal no es muy grande, por lo que las cargas de trabajo con cientos de creaciones/eliminaciones simultáneas de tablas temporales seguirán teniendo mucha contención.

Es trivial evitar la contención en las páginas de SGAM en tempdb habilitando el indicador de seguimiento documentado 1118 en el servidor, que digo que debería estar habilitado en todos los servidores del mundo, y en realidad es el comportamiento predeterminado inmutable en SQL Server 2016.

Prevenir la contención en las páginas de PFS en tempdb es un poco más difícil. Suponiendo que las tablas temporales son necesarias para el rendimiento, el truco es tener varios archivos de datos para tempdb para que las asignaciones se realicen por turnos entre los archivos, la contención se divide en varias páginas de PFS y, por lo tanto, la contención general disminuye. Desafortunadamente, no hay una respuesta correcta para la cantidad de archivos de datos que debe tener. Puede leer más sobre la orientación generalmente aceptada sobre esto en el artículo KB 2154845 y en esta publicación de blog.

Insertar punto de acceso

En las bases de datos de usuarios, una causa común de la gran cantidad de PAGELATCH_EX waits es un punto de acceso de inserción.

Esto puede ocurrir cuando una tabla tiene un índice agrupado con una clave de clúster int o bigint, y un tamaño de fila lo suficientemente pequeño como para que quepan decenas o más filas de tabla en una página de datos en el nivel de hoja del índice agrupado.

Para una tabla de este tipo, si la carga de trabajo involucra muchas decenas o cientos de subprocesos simultáneos que se insertan en la tabla, muchos de los subprocesos generarán filas con valores de identidad (y, por lo tanto, claves de clúster) que deben insertarse en la misma página de datos de nivel de hoja. .

Ahora recuerde que realizar cualquier cambio en una página de archivo de datos en la memoria requiere un pestillo exclusivo, por lo que cada uno de los subprocesos que intentan insertarse en la misma página debe adquirir el pestillo de la página exclusivamente. Mientras cada subproceso mantiene el pestillo exclusivo, los otros subprocesos estarán esperando PAGELATCH_EX para esa página, esencialmente haciendo que las inserciones simultáneas se conviertan en un proceso síncrono enormemente embotellado.

Hay algunas soluciones posibles para este problema:

  • Utilice una clave más aleatoria y reconozca que esto conducirá a la fragmentación del índice, por lo que también utilice un factor de relleno de índice para ayudar a evitar divisiones de página.
  • Separe las inserciones en la mesa utilizando algún tipo de mecanismo de división artificial
  • Utilice un tamaño de fila de tabla más largo (obviamente, esta es la opción menos aceptable)

He visto surgir un punto de acceso de inserción como este cuando alguien intentó eliminar los problemas de fragmentación del índice cambiando una clave de clúster GUID aleatoria a una clave de clúster de identidad int o bigint, pero no pudo probar el nuevo esquema de tabla bajo cargas de producción.

Resumen

Al igual que con otros tipos de espera, entender exactamente qué PAGELATCH_XX las esperas significan que es clave para entender cómo solucionarlas.

En lo que respecta a las estadísticas generales de espera, puede encontrar más información sobre cómo usarlas para solucionar problemas de rendimiento en:

  • La serie de publicaciones de mi blog SQLskills, que comienza con las estadísticas de espera o, por favor, dígame dónde le duele.
  • Mi biblioteca de tipos de espera y clases de bloqueo aquí
  • Curso de capacitación en línea My Pluralsight SQL Server:solución de problemas de rendimiento mediante estadísticas de espera
  • Asesor de rendimiento de SQL Sentry

Hasta la próxima, ¡feliz resolución de problemas!