Cómo reducir el tamaño de MSDB de 42 GB a 200 MB

Recientemente tuve un minuto libre para averiguar por qué el antiguo servidor de prueba funcionaba demasiado lento... No tuve nada que ver con eso, pero realmente quería saber qué estaba mal con el servidor.

Primero, abrí el Monitor de recursos y miré la carga total. El sqlserv.exe el proceso tomó 100% fuera UPC y genera una gran cola de discos de más de 300... mientras que un número superior a 1 se considera problemático.

Al analizar la actividad del disco, observé continuidad IO operaciones en msdb:

D:SQL_2012SYSTEMMSDBData.mdf
D:SQL_2012SYSTEMMSDBLog.ldf

Miré el tamaño msdb:

SELECT name, size = size * 8. / 1024, space_used = FILEPROPERTY(name, 'SpaceUsed') * 8. / 1024
FROM sys.database_files

y cambie al modo "facepalm":

name         size           space_used
------------ -------------- ---------------
MSDBData     42626.000000   42410.374395
MSDBLog      459.125000     6.859375

El archivo de datos es de 42 GB ... Después de un breve descanso, comencé a investigar el motivo de un tamaño tan "poco saludable" msdby cómo superar los problemas de rendimiento del servidor.

Revisé las solicitudes del costo de los recursos que se ejecutan en el servidor:

SELECT
      r.session_id
    , db = DB_NAME(r.database_id)
    , r.[status]
    , p.[text]
    --, sql_text = SUBSTRING(p.[text], (r.statement_start_offset / 2) + 1,
    --        CASE WHEN r.statement_end_offset = -1
    --            THEN 2147483647
    --            ELSE ((r.statement_end_offset - r.statement_start_offset) / 2) + 1
    --        END)
    , r.cpu_time
    , r.total_elapsed_time
    , r.reads
    , r.writes
    , r.logical_reads
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.[sql_handle]) p
WHERE r.[sql_handle] IS NOT NULL
    AND r.session_id != @@SPID
ORDER BY logical_reads DESC

En primer lugar está el procedimiento almacenado del sistema:

session_id db       status   text                                  cpu_time    total_elapsed_time reads   writes    logical_reads
---------- -------- -------- ------------------------------------- ----------- ------------------ ------- --------- ---------------
62         msdb     running  create procedure [sys].[sp_cdc_scan]  111638      6739344            618232  554324    2857923422

quiero decir Centro de Control de Enfermedades (Cambiar la recopilación de datos), que se utiliza como una herramienta para capturar cambios en los datos. Centro de Control de Enfermedades basado en la lectura del registro de transacciones y siempre funciona de forma asíncrona usando corredor de servicios.

al enviar Notificación de eventos oficina corredor de servicios, es posible que el mensaje no llegue a su destino debido a problemas de configuración y luego se archiva en una tabla separada. En general, si corredor de servicios de uso frecuente, es necesario controlar la condición sys.sysxmitqueue. Si la cantidad de datos en la tabla aumenta constantemente, es un error o estamos usando corredor de servicios incorrecto.

Plan de ejecución desde Estudio DbForge:

Plan de ejecución de dbForge Studio para SQL Server

Esta consulta devuelve la lista superior de objetos y su tamaño:

USE msdb
GO

SELECT TOP(10)
      o.[object_id]
    , obj = SCHEMA_NAME(o.[schema_id]) + '.' + o.name
    , o.[type]
    , i.total_rows
    , i.total_size
FROM sys.objects o
JOIN (
    SELECT
          i.[object_id]
        , total_size = CAST(SUM(a.total_pages) * 8. / 1024 AS DECIMAL(18,2))
        , total_rows = SUM(CASE WHEN i.index_id IN (0, 1) AND a.[type] = 1 THEN p.[rows] END)
    FROM sys.indexes i
    JOIN sys.partitions p ON i.[object_id] = p.[object_id] AND i.index_id = p.index_id
    JOIN sys.allocation_units a ON p.[partition_id] = a.container_id
    WHERE i.is_disabled = 0
        AND i.is_hypothetical = 0
    GROUP BY i.[object_id]
) i ON o.[object_id] = i.[object_id]
WHERE o.[type] IN ('V', 'U', 'S')
ORDER BY i.total_size DESC

Después de completar la consulta, recibí los siguientes resultados:

object_id   obj                               type total_rows   total_size 
----------- --------------------------------  ---- ------------ -----------
68          sys.sysxmitqueue                  S    6543502968   37188.90
942626401   dbo.sysmail_attachments           U    70           2566.00
1262627541  dbo.sysmail_attachments_transfer  U    35           2131.01
1102626971  dbo.sysmail_log                   U    44652        180.35
670625432   dbo.sysmail_mailitems             U    19231        123.39
965578478   dbo.sysjobhistory                 U    21055        69.05
366624349   dbo.backupfile                    U    6529         14.09 
727673640   dbo.sysssispackages               U    9            2.98  
206623779   dbo.backupset                     U    518          1.88  
286624064   dbo.backupfilegroup               U    3011         1.84  

Debo decir que todas las tablas de esta lista no las vamos a ignorar. Pero primero tenemos que resolver el problema con sys.sysxmitqueue.

No podemos eliminar datos directamente de sys.sysxmitqueueporque esta tabla es un objeto del sistema (S). Después de buscar un poco, encontré una manera de llegar allí. servidor SQL para quitar de la mesa. Al crear uno nuevo corredor de serviciosse eliminarán todos los mensajes relacionados con el intermediario anterior.

USE msdb
GO

ALTER Base de datos msdb SET NEW_BROKER WITH ROLLBACK IMMEDIATE

Pero antes de ejecutar el comando, se recomienda encarecidamente desactivar Agente de servidor SQL y cambiar servidor SQL oficina Modo de usuario único. Me tomó alrededor de 10 minutos eliminar los mensajes existentes en todas las colas corredor de servicios. Al finalizar, recibí el siguiente mensaje:

Nonqualified transactions are being rolled back. Estimated rollback completion: 100%.

Después de reiniciar servidor SQL el servicio todos los problemas de desempeño desaparecieron... mi corazón se llenó de alegría y pudimos ponerle fin. Pero recuerda que esta no fue la única mesa grande msdb. Veamos el resto…

Aquellos a quienes les gusta enviar correo a través de base de datos de correo debería saber esto servidor SQL registros y mantener todo el boletín msdb. Todos los archivos adjuntos de correo electrónico que se envían junto con el texto de la carta se almacenan cuidadosamente allí ... Por lo tanto, se recomienda eliminar esta información con regularidad. Esto se puede hacer con sus propias manos, es decir, preste atención a las tablas que deben eliminarse:

SELECT o.name, p.[rows]
FROM msdb.sys.objects o
JOIN msdb.sys.partitions p ON o.[object_id] = p.[object_id]
WHERE o.name LIKE 'sysmail%'
    AND o.[type] = 'U'
    AND p.[rows] > 0

Alternativamente, use procedimientos almacenados listos para usar sysmail_delete_mailitems_sp y sysmail_delete_log_sp:

DECLARE @DateBefore DATETIME 
SET @DateBefore = DATEADD(DAY, -7, GETDATE())

EXEC msdb.dbo.sysmail_delete_mailitems_sp @sent_before = @DateBefore --, @sent_status="sent"
EXEC msdb.dbo.sysmail_delete_log_sp @logged_before = @DateBefore

Historia de Agente de servidor SQL Las tareas también se almacenan en msdb. Si hay demasiadas entradas en el diario, es difícil trabajar con ellas, así que trato de limpiarlo regularmente con sp_purge_jobhistory:

DECLARE @DateBefore DATETIME 
SET @DateBefore = DATEADD(DAY, -7, GETDATE())

EXEC msdb.dbo.sp_purge_jobhistory @oldest_date = @DateBefore

También debo mencionar la información de respaldo incluida en el sistema. msdb. Las entradas de copia de seguridad antiguas se pueden eliminar usando sp_delete_backuphistory:

DECLARE @DateBefore DATETIME 
SET @DateBefore = DATEADD(DAY, -120, GETDATE())

EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = @DateBefore

Pero tenga en cuenta una cosa: cuando elimina una base de datos, la información sobre su copia de seguridad permanece en ella. msdb:

USE [master]
GO

IF DB_ID('backup_test') IS NOT NULL BEGIN
    ALTER Base de datos [backup_test] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
    DROP Base de datos [backup_test]
END
GO

CREATE Base de datos [backup_test]
GO

BACKUP Base de datos [backup_test] TO DISK = N'backup_test.bak'
GO

DROP Base de datos [backup_test]
GO

SELECT *
FROM msdb.dbo.backupset
WHERE database_name="backup_test"

En mi caso, si las bases de datos se crean y eliminan con frecuencia, esto puede conducir a la ampliación msdb. En una situación en la que la información de la copia de seguridad no sirve, se puede eliminar usando un archivo guardado. sp_delete_database_backuphistory:

EXEC msdb.dbo.sp_delete_database_backuphistory @database_name = N'backup_test'

Resumen

Sistema de bases de datos msdb utilizado por muchos componentes servidor SQLtal como corredor de servicios, Agente de servidor SQLy base de datos de correo. Cabe señalar que no existe un plan de servicio listo para usar que tenga en cuenta lo anterior, por lo que es muy importante tomar medidas preventivas regulares. En mi caso, después de borrar la información innecesaria y reducir el archivo, el tamaño msdb se convirtió en 200 MB frente a los 42 GB originales.

Espero que esta publicación sea una historia instructiva sobre los beneficios de la administración continua de las bases de datos de los usuarios y del sistema.

Artículos de interés

Subir