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

El pestillo DBCC_OBJECT_METADATA

Continuando con mi serie de artículos sobre pestillos, esta vez hablaré sobre el pestillo DBCC_OBJECT_METADATA y mostraré cómo puede ser un cuello de botella importante para las comprobaciones de coherencia antes de SQL Server 2016 en determinadas circunstancias. El problema afecta a DBCC CHECKDB, DBCC CHECKTABLE y DBCC CHECKFILEGROUP, pero para mayor claridad, solo haré referencia a DBCC CHECKDB para el resto de esta publicación.

Quizás se pregunte por qué estoy escribiendo sobre un problema que afecta a las versiones anteriores, pero todavía hay una gran cantidad de instancias de SQL Server 2014 y anteriores, por lo que es un tema válido para mi serie.

Le recomiendo encarecidamente que lea la publicación inicial de la serie antes de esta, para que tenga todos los conocimientos básicos generales sobre pestillos.

¿Qué es el pestillo DBCC_OBJECT_METADATA?

Para explicar este pestillo, necesito explicar un poco cómo funciona DBCC CHECKDB.

Entre la gran cantidad de comprobaciones de coherencia que realiza DBCC CHECKDB se encuentra una comprobación de la exactitud de los índices no agrupados. Específicamente, DBCC CHECKDB se asegura de lo siguiente:

  1. Para cada registro de índice no agrupado en cada índice no agrupado, hay exactamente un registro de datos "coincidente" en la tabla base (ya sea un montón o un índice agrupado)
  2. Para cada registro de datos en una tabla, hay exactamente un registro de índice no agrupado "coincidente" en cada índice no agrupado definido para la tabla, teniendo en cuenta los índices filtrados

Sin profundizar demasiado en los detalles de cómo se hace esto, para cada registro de datos en una tabla, DBCC CHECKDB construye cada registro de índice no agrupado que debería existir para cada índice no agrupado y se asegura de que el registro de índice no agrupado construido coincida exactamente con el registro real. registro de índice no agrupado. Si el índice no agrupado tiene una columna calculada (ya sea como parte de la clave del índice no agrupado o como una columna INCLUIDA), DBCC CHECKDB tiene que calcular el valor de la columna calculada para usar al construir los registros del índice.

Además de las comprobaciones de corrección del índice no agrupado, si hay un persistente columna calculada en la definición de una tabla, luego, para cada registro de datos en la tabla, DBCC CHECKDB debe verificar que el valor persistente sea correcto, independientemente de si esa columna es parte de un índice no agrupado o no.

Entonces, ¿cómo calcula los valores de columna calculados?

El Procesador de consultas proporciona un mecanismo para calcular los valores de columna calculados, denominado "evaluador de expresiones". DBCC CHECKDB llama a esa función, proporcionando la información de metadatos adecuada y el registro de datos, y el evaluador de expresiones usa la definición almacenada de la columna calculada en los metadatos y los valores del registro de datos y devuelve el valor de la columna calculada para que lo use DBCC CHECKDB . El funcionamiento interno del evaluador de expresiones está fuera del control del código DBCC, pero para poder utilizar el evaluador de expresiones, primero se debe adquirir un latch; el pestillo DBCC_OBJECT_METADATA.

¿Cómo se convierte el pestillo en un cuello de botella?

Aquí está el problema:solo hay un modo aceptable en el que se puede adquirir el pestillo DBCC_OBJECT_METADATA antes de usar el evaluador de expresiones, y ese es el modo EX (exclusivo). Y como sabrá al leer la publicación de introducción a la serie, solo un hilo a la vez puede sostener el pestillo en modo EX.

Juntando toda esta información:cuando una base de datos tiene columnas calculadas persistentes, o índices no agrupados que tienen columnas calculadas en ellos, se debe usar el evaluador de expresiones. Si la edición de SQL Server es Enterprise, DBCC CHECKDB puede usar el paralelismo y, por lo tanto, tiene varios subprocesos que realizan las diversas comprobaciones. Y tan pronto como tenga múltiples subprocesos intentando adquirir un latch en modo EX, ese latch se convierte en un cuello de botella. El tamaño del cuello de botella depende de cuánto se necesite usar el evaluador de expresiones, por lo que cuantas más columnas calculadas persistentes o índices no agrupados que usan columnas calculadas haya, y cuanto mayor sea el número de filas de tablas en esas tablas, el más grande es el cuello de botella que se vuelve el pestillo DBCC _OBJECT_METADATA.

Pero recuerde, este cuello de botella solo ocurre en versiones de SQL Server anteriores a SQL Server 2016. En SQL Server 2016, Microsoft decidió "arreglar" el cuello de botella desactivando las comprobaciones de índices no agrupados usando columnas calculadas de forma predeterminada y solo haciéndolas cuando el CON Se utiliza la opción EXTENDED_LOGICAL_CHECKS.

Mostrando el cuello de botella

Puede reproducir fácilmente el cuello de botella por sí mismo ejecutando DBCC CHECKDB en una base de datos que tenga columnas calculadas persistentes o índices no agrupados con columnas calculadas, y la base de datos AdventureWorks proporcionada por Microsoft es un gran ejemplo. Puede descargar copias de seguridad de AdventureWorks para su versión de SQL Server desde aquí. Realicé algunas pruebas con una base de datos AdventureWorks2014 en una instancia de SQL Server 2014 (en un Dell R720 de 32 núcleos) y amplié la base de datos a unos cientos de GB con los scripts de Jonathan.

Cuando ejecuté DBCC CHECKDB, con el servidor MAXDOP establecido en 0, tardó más de 5 horas en ejecutarse. El tipo de espera LATCH_EX representó aproximadamente el 30 % de las esperas, con cada espera de apenas 1 milisegundo, y el 99 % de las esperas LATCH_EX fueron para el latch DBCC_OBJECT_METADATA.

Busqué índices no agrupados que contuvieran columnas calculadas usando el siguiente código:

SELECT
      [s].[name] AS [Schema],
      [o].[name] AS [Object],
      [i].[name] AS [Index],
      [c].[name] AS [Column],
      [ic].*
  FROM sys.columns [c]
  JOIN sys.index_columns [ic]
      ON [ic].[object_id] = [c].[object_id]
      AND [ic].[column_id] = [c].[column_id]
  JOIN sys.indexes [i]
      ON [i].[object_id] = [ic].[object_id]
      AND [i].[index_id] = [ic].[index_id]
  JOIN sys.objects [o]
      ON [i].[object_id] = [o].[object_id]
  JOIN sys.schemas [s]
      ON [o].[schema_id] = [s].[schema_id]
  WHERE [c].[is_computed] = 1;

Ese código encontró seis índices no agrupados en la base de datos AdventureWorks2014. Deshabilité los seis índices (usando ALTER INDEX... DISABLE) y volví a ejecutar DBCC CHECKDB y se completó en unos 18 minutos. Por lo tanto, el cuello de botella del pestillo DBCC_OBJECT_METADATA fue un factor importante que hizo que DBCC CHECKDB se ejecutara más de 16 veces más lento.

Resumen

Desafortunadamente, deshabilitar los índices no agrupados usando columnas calculadas (y luego volver a habilitarlos usando ALTER INDEX … REBUILD) es la *única* forma de eliminar el cuello de botella de bloqueo DBCC_OBJECT_METADATA en versiones anteriores a SQL Server 2016 y al mismo tiempo mantener todas las demás funciones de DBCC CHECKDB. Es probable que deshabilitar los índices no agrupados no sea algo que desee hacer en un entorno de producción a menos que tenga una ventana de mantenimiento de actividad cero. Esto significa que probablemente solo desactivará esos índices no agrupados para eliminar el cuello de botella si sus comprobaciones de coherencia se descargan en otro servidor utilizando el método de copia de seguridad-copia-restauración-CHECKDB.

Otra forma de hacerlo es usar la opción CON PHYSICAL_ONLY cuando se ejecuta DBCC CHECKDB, pero luego se pierden todas las comprobaciones lógicas detalladas, por lo que no soy muy partidario de recomendar esa solución.