Temos um script que roda todas as noites, esta é a parte relevante do script:
---- Restore DB from file system
print ''
print '----------------------------------------------'
print 'Restoring Database: $(DbName)'
print ''
use master
alter database [$(DbName)] set single_user with rollback immediate
restore database [$(DbName)]
from disk = '$(BackupFile)'
with replace,
move @datalogname TO @datapath,
move @loglogname TO @logpath,
stats = 5
alter database [$(DbName)] set multi_user
alter database [$(DbName)] set new_broker with rollback immediate
print '----------------------------------------------'
Na maioria das noites funciona. Em algumas noites, ele falha com a seguinte saída:
[04:00:29] : [Step 2/7] ----------------------------------------------
[04:00:29] : [Step 2/7] Restoring Database: MYDATABASE
[04:00:29] : [Step 2/7]
[04:00:29] : [Step 2/7] Msg 3101, Level 16, State 1, Server MYSERVER, Line 83
[04:00:29] : [Step 2/7] Exclusive access could not be obtained because the database is in use.
[04:00:29] : [Step 2/7] Msg 3013, Level 16, State 1, Server MYSERVER, Line 83
[04:00:29] : [Step 2/7] RESTORE DATABASE is terminating abnormally.
[04:00:29] : [Step 2/7] Msg 1205, Level 13, State 68, Server MYSERVER, Line 89
[04:00:29] : [Step 2/7] Transaction (Process ID 73) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
[04:00:29] : [Step 2/7] Msg 5069, Level 16, State 1, Server MYSERVER, Line 89
[04:00:29] : [Step 2/7] ALTER DATABASE statement failed.
[04:00:29] : [Step 2/7] ----------------------------------------------
A linha 83 é a instrução RESTORE. A linha 89 é a set multi_user
instrução.
Por que isso está acontecendo e como podemos garantir que seja sempre bem-sucedido.
ATUALIZAR
Nenhuma transação explícita é definida no script. O script é executado a sqlcmd
partir de um arquivo. Existem vários processos fora da VM do SQL Server que estão pesquisando o banco de dados regularmente, e meu palpite é que um deles consegue se intrometer no meio set single_user
e restore
quando isso acontece. Foi sugerido que isso pode ser resolvido ativando temporariamente uma regra no firewall local que proíbe conexões de entrada, mas gostaria de saber se existe uma solução somente SQL.