A tarefa de backup agendado nem sempre faz backup de todos os bancos de dados, apesar de sempre dizer que o trabalho foi bem-sucedido

9

Eu tenho um trabalho no SQL 2008 que executa um processo armazenado para fazer backup de todos os bancos de dados. Isso é executado diariamente através do trabalho do agente do servidor sql.

É encerrado com êxito todos os dias, mas alguns dias é encerrado com sucesso somente após o backup de alguns bancos de dados. Pode ser um número diferente de bancos de dados a cada vez. Na maioria dos dias, ele faz backups com êxito de todos os bancos de dados, mas às vezes 2 backups com êxito, às vezes 5, etc.

Não vejo nenhum erro no histórico de tarefas, no visualizador de eventos ou no log do servidor sql.

Os backups estão ocorrendo em um disco local, embora a pasta seja uma "junção" para uma pasta em um volume de armazenamento expansível.

O sistema operacional é o Windows 2003 64 bits executando o Sql Server 2008 web edition de 64 bits como uma máquina virtual em execução no host Vmware ESXi 5.

Procedimento armazenado:

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

Alguma sugestão, por favor?

Andy Davies
fonte

Respostas:

9

Eu adicionaria blocos TRY / CATCH para manipular erros e registrá-los. O banco de dados pode estar em um único usuário, sendo restaurado ou o que for.

Sem isso, os erros podem abortar de forma que nenhum erro seja registrado (instrução, lote, escopo, conexão etc.)

Com TRY / CATCH, tudo exceto erros de compilação ou interrupção de conexão são registrados? mas duvido que seja esse o caso.

Eu também usaria sys.databases que substitui o sysdatabases e leu mais sinalizadores:

-- 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
fonte
+1 para o conselho para usar o sys.databases
Peter Schofield
2

Verifique se há erros após o comando "backup", envie seu próprio e-mail para detectar erros.

Isso fornecerá um ponto de partida para ver o que está acontecendo e garantirá alertá-lo sobre qualquer problema até que você resolva o problema do trabalho.

Jimbo
fonte
2

Coloque uma ordem no cursor. Já vi cursores para sys.databases terem "problemas" quando você permite que o SQL selecione a ordem em que os dados são retornados. Ordenação por nome deve ser suficiente.

Mrdenny
fonte
2

O backup está sendo executado ao mesmo tempo em que o backup em fita ou algum outro processo está copiando ou acessando os arquivos de backup? Nesse caso, aposto que está falhando em substituir o arquivo porque está em uso. Se você tiver espaço para várias cópias de backup, poderá alterar seu processo para adicionar um carimbo de data ao arquivo de saída, mas precisará de uma rotina de limpeza.

SqlACID
fonte
Não que eu saiba. O backup é feito localmente e depois é feito fora do local algumas horas depois.
Andy Davies
0

Com a introdução do SQL Server 2005, o cursor percorreu sysdatabases e até sys.databases parecia mudar, por isso não era confiável - e essa mudança de comportamento também pode ser vista com sp_foreachdb.

Achei que mudar o tipo de cursor ajudou (acho que foi rápido), mas no final mudei para soluções como a solução de manutenção e backup de Ola Hallengren. Como a maioria das coisas críticas, como backups, você ainda precisa fazer uma verificação cruzada de todos os bancos de dados para garantir o backup mesmo com essas soluções em potencial - e você obviamente fez isso, muito bem!

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

Solução de manutenção da Ola: http://ola.hallengren.com/

Peter Schofield
fonte
0

Eu tive o mesmo problema, especialmente ao fazer backup de bancos de dados grandes.

@@fetch_statusé uma variável GLOBAL, portanto, pode ser alterada (definida como 0) por outro cursor que não o seu. Eu o resolvi fazendo o seguinte (em 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
fonte
-1

Eu tentei descobrir esse problema e parece que muitas vezes os usuários postaram a solução que, se você tornar a declaração do cursor insensível, ela começará a funcionar. Então eu testei e sim, apenas certifique-se de que o cursor declare estático e comece a funcionar.

O fato pelo qual falha é: - Verifique a configuração de limite do cursor no nível do servidor - se estiver configurado como -1, significa que todos os cursores estão sendo preenchidos de forma síncrona em outras palavras, enquanto tentam ler os dados do conjunto de teclas do cursor são síncronos e tudo tenta leia ao mesmo tempo. Se alterarmos esse valor para 0, que informa ao SQL Server para preencher uma população assíncrona em palavras simples, o cursor pode buscar os registros enquanto o conjunto de chaves ainda está sendo preenchido e você verá que, após fazer essa alteração no nível do servidor, nunca perderá nenhum banco de dados usando cursores.

Soluções: declare a estática do cursor ou altere a configuração no nível do servidor "Limite do cursor" para 0 de -1.

Obrigado, Gaurav Mishra | DBA Sênior

user44716
fonte