La tarea de copia de seguridad programada no siempre hace una copia de seguridad de todas las bases de datos a pesar de que siempre dice que el trabajo fue exitoso

9

Tengo un trabajo en SQL 2008 que ejecuta un proceso almacenado para hacer una copia de seguridad de todas las bases de datos. Esto se ejecuta diariamente a través del trabajo del agente del servidor sql.

Se cierra con éxito todos los días, pero algunos días se cierra con éxito solo después de hacer una copia de seguridad de algunas bases de datos. Puede ser un número diferente de bases de datos cada vez. La mayoría de los días realiza una copia de seguridad de todas las bases de datos, pero a veces 2 copias de seguridad con éxito, a veces 5, etc.

No veo ningún error en el historial de trabajos, el visor de eventos o el registro del servidor sql.

Las copias de seguridad se realizan en un disco local, aunque la carpeta es una "unión" a una carpeta en un volumen de almacenamiento expandible.

El sistema operativo es Windows 2003 de 64 bits que ejecuta Sql Server 2008 web edition de 64 bits como una máquina virtual que se ejecuta en el host Vmware ESXi 5.

Procedimiento almacenado:

ALTER PROCEDURE [dbo].[backup_all_databases] 
@path VARCHAR(255)='c:\backups\'

AS

DECLARE @name VARCHAR(50) -- database name  
DECLARE @fileName VARCHAR(256) -- filename for backup  
DECLARE @fileDate VARCHAR(20) -- used for file name 
DECLARE @dbIsReadOnly sql_variant -- is database read_only?
DECLARE @dbIsOffline sql_variant -- is database offline?

DECLARE db_cursor CURSOR FOR  
SELECT name 
FROM master.dbo.sysdatabases 
WHERE name NOT IN ('tempdb')
AND version > 0 AND version IS NOT NULL

OPEN db_cursor   
FETCH NEXT FROM db_cursor INTO @name   

WHILE @@FETCH_STATUS = 0   
BEGIN   
SET @fileName = @path + @name + '.bak'

SET @dbIsReadOnly = (SELECT DATABASEPROPERTY(@name, 'IsReadOnly')) -- 1 = Read Only
SET @dbIsOffline = (SELECT DATABASEPROPERTY(@name, 'IsOffline')) -- 1 = Offline

IF (@dbIsReadOnly = 0 OR @dbIsReadOnly IS NULL) AND @dbIsOffline =0
BEGIN
    BACKUP DATABASE @name TO DISK = @fileName  WITH INIT
    WAITFOR DELAY '00:00:20'
END

FETCH NEXT FROM db_cursor INTO @name 
END   

CLOSE db_cursor   
DEALLOCATE db_cursor

¿Alguna sugerencia por favor?

Andy Davies
fuente

Respuestas:

9

Agregaría bloques TRY / CATCH para manejar errores y registrarlos. El DB podría estar en un solo usuario, ser restaurado o lo que sea.

Sin esto, los errores pueden abortarse de forma tal que no se registren errores (declaración, lote, alcance, conexión, etc.)

Con TRY / CATCH, ¿se registran todos los errores de cancelación de compilación o conexión? pero dudo que este sea el caso.

También usaría sys.databases que reemplaza sysdatabases y lee más indicadores:

-- declares etc

BEGIN TRY

    DECLARE db_cursor CURSOR FOR  
    SELECT name, state, user_access
    FROM sys.databases 
    WHERE name NOT IN ('tempdb')

    OPEN db_cursor   
    FETCH NEXT FROM db_cursor INTO @name, @state, @user_access

    WHILE @@FETCH_STATUS = 0   
    BEGIN   

        SET @fileName = @path + @name + '.bak'
        IF @state = 0 AND user_access = 0
        BEGIN
            BEGIN TRY
                BACKUP DATABASE @name TO DISK = @fileName  WITH INIT
            END TRY
            BEGIN CATCH
                -- log but do not rethrow so loop continues
            END CATCH
            WAITFOR DELAY '00:00:20'
        END
        ELSE
           --log user and/or state issues

        FETCH NEXT FROM db_cursor INTO @name 
    END   

    CLOSE db_cursor   
    DEALLOCATE db_cursor

END TRY
BEGIN CATCH
  -- some useful stuff here
END CATCH
gbn
fuente
+1 por los consejos para usar sys.databases
Peter Schofield
2

Compruebe si hay errores después del comando "copia de seguridad", envíe su propio correo electrónico para detectar cualquier error detectado.

Esto le dará un punto de partida para ver lo que está sucediendo y garantizará alertarlo de cualquier problema hasta que resuelva el problema del trabajo.

Jimbo
fuente
2

Poner una orden en el cursor. He visto que los cursores de sys.databases tienen "problemas" cuando permite que SQL seleccione el orden en que se devuelven los datos. Ordenar por nombre debería ser suficiente.

mrdenny
fuente
2

¿La copia de seguridad se ejecuta al mismo tiempo que la copia de seguridad en cinta o algún otro proceso de copia o acceso a los archivos de copia de seguridad? Si es así, apuesto a que no se puede sobrescribir el archivo porque está en uso. Si tiene espacio para varias copias de seguridad, puede cambiar su proceso para agregar una marca de fecha al archivo de salida, pero luego necesitará una rutina de limpieza.

SqlACID
fuente
No que yo supiese. La copia de seguridad se realiza localmente y luego rsync-ed fuera del sitio unas horas más tarde.
Andy Davies
0

Con la introducción de SQL Server 2005, el cursor en bucle a través de sysdatabases e incluso sys.databases pareció cambiar, por lo que no fue confiable, y este cambio en el comportamiento también se pudo ver con sp_foreachdb.

Descubrí que cambiar el tipo de cursor ayudó (creo que fue un avance rápido), pero finalmente cambié a soluciones como la solución de respaldo y mantenimiento de Ola Hallengren. Como la mayoría de las cosas que son críticas, como las copias de seguridad, aún necesita verificar todas las bases de datos para asegurarse de que estén respaldadas incluso con estas posibles soluciones, ¡y obviamente lo hizo, muy bien!

Tipos de cursor: http://msdn.microsoft.com/en-us/library/ms378405(v=SQL.90).aspx

Solución de mantenimiento de Ola: http://ola.hallengren.com/

Peter Schofield
fuente
0

Tuve el mismo problema, especialmente al hacer una copia de seguridad de grandes bases de datos.

@@fetch_statuses una variable GLOBAL, por lo que podría modificarse (establecerse en 0) por otro cursor que no sea el suyo. Lo resolví haciendo lo siguiente (en pseudocódigo):

create a temp table with dbNames
select top 1 in a variable (use order by)
while variable is null
do your thing

set variable = null
delete top 1(use order by)
select top 1 in a variable (use order by)
loop
Gerrit
fuente
-1

He intentado resolver este problema y parece que muchas veces los usuarios publicaron la solución de que si hace que la declaración del cursor sea insensible, entonces comienza a funcionar. Así que lo probé y sí, solo se asegura de que la declaración del cursor sea estática y comience a funcionar.

El hecho por el que falla es: compruebe la configuración del umbral del cursor a nivel del servidor; si está configurado como -1, significa que todos los cursores se llenan sincrónicamente en otras palabras mientras intenta leer los datos del conjunto de teclas del cursor que están sincronizados y todo se intenta leer al mismo tiempo Si cambiamos este valor a 0 que le dice al servidor SQL que haga una población asincrónica en palabras simples, el cursor puede recuperar los registros mientras el conjunto de claves aún estará poblado y verá que después de hacer este cambio a nivel del servidor, nunca perderá ninguna base de datos usando cursores

Soluciones: declare el cursor estático o cambie la configuración de nivel del servidor "Umbral del cursor" a 0 desde -1.

Gracias Gaurav Mishra | Senior DBA

usuario44716
fuente