O Database Snaphot (ou “instantâneo de Banco de Dados”, se você estiver no SQL Server em português – Que nome terrível, hehehe) é um banco de dados _somente leitura, _onde o SQL Server guarda os dados originais de tudo o que está sendo alterado pelos usuários, para que seja possível realizar verificações (dentre outras coisas) de como estava o banco antes destas ocorrerem.
Ao contrário do que muita gente pensa, as alterações ocorrem nas páginas de dados e não no objeto que está sofrendo alteração. O SQL Server utiliza um recurso chamado “Copy-on-write” onde, antes da página ser alterada, os dados originais são armazenados no snapshot.
A minha ideia incial era tentar mostrar dentro das páginas de dados quando estaríamos acessando o banco original (consultando o snapshot) e quando estaríamos vendo os dados alterados e enviados para o snapshot, porém em conversa com o grande Luciano Moreira (twitter | blog), ele me falou que isso não era possível (após um papo com o Paul Randal… Loucura esse mundo, ehehe), que cada página fica em um mapa de bits na memória e que para buscar isso apenas usando um debugger no SQL Server… Aí já viu né… Ficamos assim, hehehehe
Abaixo, tentarei demonstrar o funcionamento do snapshot… Mas vou tentar fazer algo diferente: ao invés de jogar todo o script, vou colocar ele por blocos e, no final, disponibilizo o script para download. Depois me digam o que acharam.
Primeiro, vamos criar a base e inserir alguns dados…
/*
Criando o banco, a tabela e inserindo alguns registros...
*/
CREATE DATABASE DatabaseSnapshot
CREATE DATABASE Origem
ON (NAME ='Origem_Data',
FILENAME = N'D:\Bases\DatabaseSnapshot\Origem_Data.mdf')
LOG
ON (NAME = 'Origem_Log',
FILENAME = N'D:\Bases\DatabaseSnapshot\Origem_Log.ldf')
GO
USE Origem
CREATE TABLE Pessoa (Codigo int identity(1,1), Nome char(2000), nascimento date)
GO
INSERT INTO Pessoa
VALUES ('Logan', '1981-05-25'), ('Kratos', '1980-05-25'),
('Cronos', '1979-05-25'), ('Brucilí', '1980-07-25'),
('Fulano', '1980-07-25')Vejam que eu criei a coluna Nome como char(2000), apenas para que alguns registros estejam em cada página de dados (entenda o que é uma página de dados aqui).
Feito isso, vamos criar um snapshot:
/* Criação do Snapshot do Banco Origem */ CREATE DATABASE DatabaseSnapshot ON (name = DBSS_Data , FILENAME = 'D:\Bases\DatabaseSnapshot\DBSS_Data.ss') AS SNAPSHOT OF Origem
Notem a sintaxe da criação do snapshot… Ela é muito semelhante com a de criação de um banco comum, com exceção do Log (que não existe no snapshot) e a informação do banco de origem (AS SNAPSHOT OF …). E aos que estão querendo saber como fazer pelo SSMS, eu sinto muito, mas não é possível. Tem que ser na munheca mesmo (e nem é tão complicado assim, vai).
Com isso, a nossa estrutura ficou assim, até o momento:

Dando uma olhada nas propriedades do .ss que foi criado dá pra ver que o arquivo está praticamente vazio, apesar de uma consulta no banco trazer os dados normalmente (faça um select para confirmar). Isso ocorre pois o snapshot trabalha com o conceito de Sparse Files. Veja a imagem abaixo:

Agora, vamos alterar um registro, apagar outro e inserir um novo e, então, vamos comparar com o snapshot para ver o resultado:
/*
Alteração de alguns dados na base de origem
*/
UPDATE Pessoa
SET nome = 'Logan Merazzi', nascimento = '2013-04-10'
WHERE Codigo = 1
DELETE FROM Pessoa WHERE Codigo = 5
INSERT INTO Pessoa VALUES ('Waldisnei','1985-05-30')
Viram os valores originais no snapshot?
Com isso, a estrutura passou para a seguinte situação:

É possível realizar a criação de “N” snapshots, um para cada momento desejado.
Vamos criar um novo snapshot, fazer algumas alterações, comparar o resultados novamente e então partir pra exclusão e restauração…
/*
Criação de um Segundo Snapshot, para podermos consultar os estados...
*/
CREATE DATABASE DatabaseSnapshot_V2
ON
(name = Data , FILENAME = 'D:\Bases\DatabaseSnapshot\DBSSV2_Data.ss')
AS
SNAPSHOT OF Origem
GO
update Pessoa
set nome = RTRIM(Nome) + ' A', nascimento = '2020-10-10'
where Codigo in (3,6)
-- Comparando
SELECT POrig.Codigo, POrig.Nome, POrig.nascimento,
PSnap.Codigo, PSnap.Nome, PSnap.nascimento,
PSnap2.Codigo, PSnap2.Nome, PSnap2.nascimento
FROM Pessoa POrig
FULL JOIN DatabaseSnapshot.dbo.Pessoa PSnap
ON (POrig.Codigo = PSnap.Codigo)
FULL JOIN DatabaseSnapshot_V2.dbo.Pessoa PSnap2
ON (POrig.Codigo = PSnap2.Codigo)
A sintaxe para restaurar um snapshot é a seguinte:
RESTORE DATABASE DatabaseSnapshot FROM DATABASE_SNAPSHOT = 'DatabaseSnapshot';
Porém é importante frisar que para a restauração funcionar, deve existir apenas um snapshot associado, desta forma, todos os demais snapshots devem ser excluídos.
/* Vamos restaurar o snapshot para a posição original... */ use master RESTORE DATABASE Origem FROM DATABASE_SNAPSHOT = 'DatabaseSnapshot'; -- Erro? -- Precisamos dropar os demais snapshots... DROP DATABASE DatabaseSnapshot_V2 -- E agora? Vai? RESTORE DATABASE Origem FROM DATABASE_SNAPSHOT = 'DatabaseSnapshot'; select * from DatabaseSnapshot.dbo.Pessoa select * from Origem.dbo.Pessoa
Com a base restaurada a partir do snapshot, vejam que a base voltou para o mesmo estado do início do post.
Considerações:
- Snapshot não substitui backup. Ele ajuda para restaurações pontuais, porém como o snapshot é diretamente dependente da base original (você não consegue apagar o banco ou restaurá-lo se houver um snapshot associado), qualquer erro que ocorra na base original (base corrompida, falha no disco, etc), os dados não estarão mais seguros.
- Para criação de bases de testes, homologação e demonstração é uma mão na roda… voltar uma base de um snapshot, dependendo do tamanho da base, é muito mais rápido. Sem contar que as comparações das alterações se tornam muito mais simples de serem verificadas.
- Esse recurso está disponível a partir da versão 2005 do SQL Server, porém apenas na edição Enterprise (ou Developer).
- A complexidade de administração aumenta um pouco, pois você tem que prestar muita atenção quando houverem vários snapshots criados para saber qual ponto restaurar e avaliar a perda do “histórico”.
- Você terá um aumento considerável de I/O de disco… então use-o com sabedoria.
Bom, fico por aqui… Façam as suas considerações e vamos discutindo.
O script completo está aqui. Enjoy!
[]’s!