¿Se pueden desfragmentar las tablas del sistema SQL Server?

15

Tenemos varias bases de datos en las que se crean y descartan una gran cantidad de tablas. Por lo que podemos decir, SQL Server no realiza ningún mantenimiento interno en las tablas base del sistema , lo que significa que pueden fragmentarse con el tiempo y aumentar de tamaño. Esto ejerce una presión innecesaria sobre el grupo de búferes y también afecta negativamente el rendimiento de las operaciones, como calcular el tamaño de todas las tablas de una base de datos.

¿Alguien tiene sugerencias para minimizar la fragmentación en estas tablas internas básicas? Una solución obvia podría ser evitar crear tantas tablas (o crear todas las tablas transitorias en tempdb), pero para el propósito de esta pregunta, digamos que la aplicación no tiene esa flexibilidad.

Editar: La investigación adicional muestra esta pregunta sin respuesta , que parece estar estrechamente relacionada e indica que alguna forma de mantenimiento manual ALTER INDEX...REORGANIZEpuede ser una opción.


Investigación inicial

Los metadatos sobre estas tablas se pueden ver en sys.dm_db_partition_stats:

-- The system base table that contains one row for every column in the system
SELECT row_count,
    (reserved_page_count * 8 * 1024.0) / row_count AS bytes_per_row, 
    reserved_page_count/128. AS space_mb
FROM sys.dm_db_partition_stats
WHERE object_id = OBJECT_ID('sys.syscolpars')
    AND index_id = 1
-- row_count:       15,600,859
-- bytes_per_row:   278.08
-- space_mb:        4,136

Sin embargo, sys.dm_db_index_physical_statsno parece admitir la visualización de la fragmentación de estas tablas:

-- No fragmentation data is returned by sys.dm_db_index_physical_stats
SELECT *
FROM sys.dm_db_index_physical_stats(
    DB_ID(),
    OBJECT_ID('sys.syscolpars'),
    NULL,
    NULL,
    'DETAILED'
)

Los scripts de Ola Hallengren también contienen un parámetro para considerar la desfragmentación de los is_ms_shipped = 1objetos, pero el procedimiento ignora silenciosamente las tablas base del sistema incluso con este parámetro habilitado. Ola aclaró que este es el comportamiento esperado; solo se consideran las tablas de usuario (no las tablas del sistema) que se envían ms (por ejemplo msdb.dbo.backupset).

-- Returns code 0 (successful), but does not do any work for system base tables.
-- Instead of the expected commands to update statistics and reorganize indexes,
-- no commands are generated. The script seems to assume the target tables will
-- appear in sys.tables, but this does not appear to be a valid assumption for
-- system tables like sys.sysrowsets or sys.syscolpars.
DECLARE @result int;
EXEC @result = IndexOptimize @Databases = 'Test',
        @FragmentationLow = 'INDEX_REORGANIZE',
        @FragmentationMedium = 'INDEX_REORGANIZE',
        @FragmentationHigh = 'INDEX_REORGANIZE',
        @PageCountLevel = 0,
        @UpdateStatistics = 'ALL',
        @Indexes = '%Test.sys.sysrowsets.%',
        -- Proc works properly if targeting a non-system table instead
        --@Indexes = '%Test.dbo.Numbers.%',
        @MSShippedObjects = 'Y',
        @Execute = 'N';
PRINT(@result);


Información adicional solicitada

Utilicé una adaptación de la consulta de Aaron debajo del uso del grupo de búfer de inspección de la tabla del sistema, y ​​descubrí que hay decenas de GB de tablas del sistema en el grupo de búfer para solo una base de datos, con ~ 80% de ese espacio siendo espacio libre en algunos casos .

-- Compute buffer pool usage by system table
SELECT OBJECT_NAME(p.object_id),
    COUNT(b.page_id) pages,
    SUM(b.free_space_in_bytes/8192.0) free_pages
FROM sys.dm_os_buffer_descriptors b
JOIN sys.allocation_units a
    ON a.allocation_unit_id = b.allocation_unit_id
JOIN sys.partitions p
    ON p.partition_id = a.container_id
    AND p.object_id < 1000 -- A loose proxy for system tables
WHERE b.database_id = DB_ID()
GROUP BY p.object_id
ORDER BY pages DESC

ingrese la descripción de la imagen aquí

Geoff Patterson
fuente

Respuestas:

11

¿Está seguro de haber identificado de manera positiva y precisa esta tabla del sistema como la única fuente de "presión innecesaria sobre el grupo de búferes y también tiene un impacto negativo en el rendimiento de las operaciones, como calcular el tamaño de todas las tablas en una base de datos"? ¿Está seguro de que esta tabla del sistema no se autogestiona de tal manera que (a) la fragmentación se minimice o se mantenga bajo control en secreto o simplemente (b) se administre eficientemente en la memoria para que los niveles de desfragmentación realmente no afecten mucho?

Puede ver cuántas páginas están en uso y puede ver cuánto espacio libre hay en las páginas que están en la memoria ( page_free_space_percentsiempre está NULLen las asignaciones DMF, pero esto está disponible desde el búfer DMV); esto debería darle alguna idea si lo que te preocupa es realmente algo de lo que deberías preocuparte:

SELECT 
  Number_of_Pages = COUNT(*), 
  Number_of_Pages_In_Memory = COUNT(b.page_id),
  Avg_Free_Space = AVG(b.free_space_in_bytes/8192.0) 
FROM sys.dm_db_database_page_allocations
(
  DB_ID(),
  OBJECT_ID(N'sys.syscolpars'),
  NULL,NULL,'DETAILED'
) AS p
LEFT OUTER JOIN sys.dm_os_buffer_descriptors AS b
ON b.database_id = DB_ID() 
AND b.page_id = p.allocated_page_page_id 
AND b.file_id = p.allocated_page_file_id;

Si su número de páginas es pequeño (como probablemente <10000 para las tablas del sistema) o si el espacio libre es "bajo" (no está seguro de cuáles son sus umbrales típicos para reorganizar / reconstruir), concéntrese en otra fruta más interesante y baja .

Si su número de páginas es grande y el espacio libre es "alto", está bien, entonces tal vez le estoy dando demasiado crédito a SQL Server por su propio mantenimiento. Como mostró de la otra pregunta , esto funciona ...

ALTER INDEX ALL ON sys.syscolpars REORGANIZE;

... y hace disminuir la fragmentación. Aunque puede requerir permisos elevados (no lo intenté como peón).

Tal vez pueda hacer esto periódicamente como parte de su propio mantenimiento, si lo hace sentir bien y / o tiene alguna evidencia de que tiene algún impacto positivo en su sistema.

Aaron Bertrand
fuente
Agregué otra respuesta que resume lo que terminamos haciendo, y luego limpié los comentarios anteriores aquí. ¡De nuevo, gracias por tu ayuda!
Geoff Patterson
7

Basado en la guía de la respuesta de Aaron, así como en investigaciones adicionales, aquí hay una descripción rápida del enfoque que tomé.

Por lo que puedo decir, las opciones para inspeccionar la fragmentación de las tablas base del sistema son limitadas. Seguí adelante y presenté un problema de Connect para proporcionar una mejor visibilidad, pero mientras tanto parece que las opciones incluyen cosas como examinar el grupo de búferes o verificar el número promedio de bytes por fila.

Luego creé un procedimiento para realizar `ALTER INDEX ... REORGANIZE en todas las tablas base del sistema . La ejecución de este procedimiento en algunos de nuestros servidores de desarrollo más (ab) utilizados mostró que el tamaño acumulativo de las tablas base del sistema se redujo hasta en 50 GB (con ~ 5MM de tablas de usuario en el sistema, por lo que claramente es un caso extremo).

Una de nuestras tareas de mantenimiento nocturno, que ayuda a limpiar muchas de las tablas de usuarios creadas por varias pruebas unitarias y desarrollo, antes tardaba unos 50 minutos en completarse. Una combinación de sp_whoisactive, sys.dm_os_waiting_tasksy DBCC PAGEmostró que las esperas estaban dominadas por E / S en las tablas base del sistema.

Después de la reorganización de todas las tablas base del sistema, la tarea de mantenimiento se redujo a ~ 15 minutos. Todavía había algunas esperas de E / S, pero se redujeron significativamente, tal vez debido a una mayor cantidad de datos que permanecen en la memoria caché y / o más leídos debido a una menor fragmentación.

Por lo tanto, mi conclusión es que agregar ALTER INDEX...REORGANIZEtablas base del sistema en un plan de mantenimiento puede ser algo útil a considerar, pero probablemente solo si tiene un escenario en el que se está creando una cantidad inusual de objetos en una base de datos.

Geoff Patterson
fuente
+1 tanto para su pregunta como para la respuesta: las partes internas son un poco como una caja negra, y ha ayudado a arrojar algo de luz sobre lo que parece un escenario realmente desagradable para el rendimiento (incluso si el suyo es un caso marginal).
Max Vernon