Olá,
Como descobrir a verdadeira data de criação de um banco de dados? A princípio, parece ser uma pergunta simples de responder e a resposta aparece de quase imediato: veja na create_date da sys.databases. Mas estamos falando da verdadeira data de criação de um banco de dados, aquela que permanece a mesma mesmo se for a base restaurada em uma instância diferente.
A verdade é que depende. Depende da versão do produto em que o banco de dados foi originado.
IMPORTANTE: O post faz referência a vários comandos e dados não documentados, como DBCC PAGE, metadados das páginas, etc. Use por sua conta em risco…
Início dos testes
Nosso objetivo aqui é mostrar o verdadeiro significado do campo create_date da sys.databases e mostrar que ela não é tão confiável assim para descobrir a real data de criação de uma base e que essa informação está disponível através da boot page no próprio banco de dados, porém depende da versão do SQL Server na qual o banco foi criado.
O servidor utilizada para testes roda o SQL Server 2008 R2 Enterprise Edition.
-- Criando a base de testes CREATE DATABASE MinhaBaseMinhaVida -- Vamos checar a data de criação da base SELECT NAME, CREATE_DATE FROM SYS.DATABASES D WHERE NAME = 'MinhaBaseMinhaVida' -- 2014-10-31 10:09:34.520
Até aqui nada demais… A data de criação da base neste momento que a sys.databases nos trouxe é fidedigna (porque a base foi criada diretamente e não foi restaurada). Então aqui, a informação passada pela sys.databases é verdadeira, confere com a real criação da base.
Vide quadro abaixo:
NAME |
CREATE_DATE |
MinhaBaseMinhaVida |
2014-10-31 10:09:34.520 |
Boot Page (aka página 9)
Todo banco de dados possui uma Boot Page, que corresponde a página de número 9 do arquivo de dados primário e nela contêm informações essenciais (pra não dizer informações críticas) para sobre o banco de dados em questão. Essa página é obrigatória para operações de inicialização da base e se a mesma for corrompida e não houver backups para restaurá-la em caso de desastre, só um milagre (ou habillidade apurada para recuperação de corrupções) resolverá o problema. Das várias informações úteis sobre o banco de dados, podemos supor que se em algum lugar é registrada a informação da verdadeira data de criação de um banco de dados, existem grandes chances desta informação estar na boot page. Vamos investigar…
DBCC TRACEON(3604) DBCC PAGE ('MinhaBaseMinhaVida',1,9,3)
Campo de interesse: dbi_crdate
Tirando um backup da base, vamos checar as informações através do cabeçalho do arquivo de backup:
RESTORE HEADERONLY FROM DISK = 'C:TEMPMinhaBaseMinhaVida.BAK'
A data do campo DatabaseCreationDate equivale à data identificada no create_date, desconsiderando os milésimos.
Vamos restaurar o backup e observar o que realmente muda:
RESTORE DATABASE MinhaBaseMinhaVida from DISK = 'C:TEMPMinhaBaseMinhaVida.BAK' SELECT NAME, CREATE_DATE FROM SYS.DATABASES D WHERE NAME = 'MinhaBaseMinhaVida' -- 2014-10-31 10:19:05.993
NAME |
CREATE_DATE |
MinhaBaseMinhaVida |
2014-10-31 10:19:05.993 |
A data de criação da base mudou pra data de restauração. Confere, produção?
SELECT * FROM MSDB.DBO.RESTOREHISTORY R WHERE R.destination_database_name = 'MinhaBaseMinhaVida'
destination_database_name |
restore_date |
MinhaBaseMinhaVida |
2014-10-31 10:19:05.867 |
Consultando a Boot page:
DBCC PAGE ('MinhaBaseMinhaVida',1,9,3)
Aqui descobrimos o real significado da dbi_crdate: a data de criação da base naquela instância, que pode ser um create ou um restore, e por isso, não é uma data totalmente confiável…Um teste interessante pra ser feito por fora, é que se formos restaurar a base sobrescrevendo a antiga (com o uso efetivo do comando with replace) o dbi_crdate não será atualizado.
Mas ainda na boot page, temos outra data que deve ser verificada…
Destacando:
m_fSeqNo = 26 m_blockOffset = 104 m_slotId = 64
dbi_dbccLastKnownGood = 1900-01-01 00:00:00.000 dbi_modDate = 2014-10-31 10:09:35.737
O campo dbi_modDate é similar à verdadeira data de criação inicial da base. O nome pode nos levar a pensar que essa data deve estar relacionada apenas à modificações na estrutura no banco de dados em questão mas podemos provar que de fato é a data que estamos procurando.
Vamos realizar alguns testes com a query abaixo. Ela faz um leitura na boot page e filtra somente campos que contenham date no nome. A ideia aqui é facilitar nossa vida e trazer o resultado em um formato mais amigável pra gente. Lembrando que usar dbcc page utilizando tableresults dispensa a necessidade de ativar o TF3604.
DECLARE @VAR AS TABLE ( ParentObject varchar(max), Object varchar(max), Field varchar(max), value varchar(max) ) INSERT INTO @VAR EXEC ('DBCC PAGE (''MinhaBaseMinhaVida'',1,9,3) WITH TABLERESULTS') SELECT field, value FROM @VAR WHERE FIELD LIKE '%DATE%'
Field |
value |
dbi_crdate |
2014-10-31 10:19:05.993 |
dbi_modDate |
2014-10-31 10:09:35.737 |
Vamos realizar algumas modificações na estrutura da base pra ver se a tal da modDate é atualizada…
ALTER DATABASE MinhaBaseMinhaVida SET COMPATIBILITY_LEVEL = 80 -- Estava em 100 ALTER DATABASE MinhaBaseMinhaVida SET RECOVERY SIMPLE ALTER DATABASE MinhaBaseMinhaVida ADD FILE (name= 'data2', filename = 'c:tempdata2.ndf')
Se executarmos a query de verificação, vamos observar que as ambas as datas permanecem as mesmas.
Vamos fazer agora um attach e dettach e observar as datas.
NAME |
CREATE_DATE |
MinhaBaseMinhaVida |
2014-10-31 11:14:23.623 |
A data de criação foi alterada na sys.databases. Ela corresponde agora ao exato momento em que o Attach ocorreu.
Vamos usar aquela consulta para verificar as data da boot page:
Field |
value |
dbi_crdate |
2014-10-31 10:19:05.993 (mesma data de antes e não é a do attach!) |
dbi_modDate |
2014-10-31 10:09:35.737 (Firme e forte, sem mudanças) |
E aqui outra descoberta! dbi_crdate não foi alterada mesmo com o attach. Isso derruba o mito (que parece ser intuitivo até…) de que a dbi_crdate sempre será equivalente à data da create_date da sys.databases.
Um último teste…fazer backup da base e restaurar em outra instância e conferir as datas…
RESTORE DATABASE MinhaBaseMinhaVida FROM DISK = 'C:TEMPMinhaBaseMinhaVida.BAK' WITH MOVE 'MinhaBaseMinhaVida' TO 'C:TEMPMD.MDF', MOVE 'MinhaBaseMinhaVida_log' TO 'C:TEMPMD.LOG'
Field |
value |
dbi_crdate |
2014-10-31 11:31:33.103 (alterou!) |
dbi_modDate |
2014-10-31 10:09:35.737 (permaneceu) |
Observe que agora a dbi_crdate foi alterada pois reflete a data de criação da base naquela instância (na prática, o restore é a criação de uma base… mas notem que a dbi_modDate permanece a mesma!
Podemos concluir que a dbi_modDate é a data de criação definitiva e imutável de uma determinada base.
Certo?
Depende. Infelizmente, nem sempre poderemos contar com essa data…
O campo dbi_Moddate e o SQL Server 2000
Em nosso ambiente, tinhamos a tarefa de identificar a data real de criação das bases do ambiente de produção, e checando a dbi_moddate topamos com uma data aparentemente padrão: 1900-01-01 e algumas poucas com datas diversas. A informação que temos é que as bases que possuem dbi_moddate datando em 1900 são bases que vieram do SQL Server 2000. Vamos executar alguns testes e entender o que acontece:
O nosso cenário é um pouco diferente… A data está com valor default (de ano 1900). Sabemos que a base foi migrada de um servidor SQL Server 2000. Vamos refazer os mesmos procedimentos em uma base SQL 2000 então.
CREATE DATABASE MinhaBaseMinhaVida go SELECT * FROM sysdatabases d where d.name = 'MinhaBaseMinhaVida' -- 2014-10-31 11:37:40.680 dbcc traceon (3604) dbcc page ('MinhaBaseMinhaVida',1,9,3) Uma importante descoberta aqui....
Algo importante de ser notado:
Cadê o dbi_moddate? Ele não existe nas boot pages do SQL Server 2005 e inferior (o que inclui 2000).
Próximos passos:
- No SQL Server 2000: tirar backup da base MinhaBaseMinhaVida;
- Restaurar a base no SQL Server 2008R2 (Restaurei com o nome MinhaBaseMinhaVida2000)
DECLARE @VAR AS TABLE ( ParentObject varchar(max), Object varchar(max), Field varchar(max), value varchar(max) ) INSERT INTO @VAR EXEC ('DBCC PAGE (''MinhaBaseMinhaVida2000'',1,9,3) WITH TABLERESULTS') SELECT Field, value FROM @VAR WHERE FIELD LIKE '%DATE%'
Field | value |
dbi_crdate | 2014-10-31 14:11:25.203 |
dbi_modDate | 1900-01-01 00:00:00.000 |
1900-01-01 é a data padrão para o dbi_modDate para bases que foram restauradas de versões anteriores ao SQL Server 2008. Significa que para bases que sejam de versões anteriores, você não pode confiar neste campo.
Afinal, em que data posso confiar?
Alguns dos métodos disponíveis (os mais úteis) e algumas considerações em específico:
- Dbi_crdate (boot page): É a data de criação da base naquela instância em específico. Não é totalmente confiável pois a base pode ter sido restaurada de outro servidor;
- Dbi_moddate(boot page): É a data “definitiva” de criação da base. Se ela existir, é confiável e portanto, presentes em bases criadas à partir do SQL Server 2008, contando que essa data nunca tenha sido alterada na mão, já que é possível alterar conteúdo das páginas do SQL Server o que em geral é uma má (e perigosa) ideia;
- Create_date (sys.databases): Data do último restore ou attach. Não é totalmente confiável por motivos já explicados, embora seja extensamente utilizada no mundo afora para respostas rápidas.
- A data mais antiga que você encontrar na sys.objects de determinada base (independente do objeto, desde de que ele seja criado por usuário e não de sistema, seja proc, tabela, function, etc) pode ser a mais próxima da data de criação de base, porém é muito raro e pouco provável que alguém vá criar uma base sem objeto algum. O ruim é que essa abordagem possui dois poréns:
1) Objetos podem ser dropados, então não necessariamente as datas são 100% confiáveis;
2) O banco de dados em questão pode ter sido criado usando uma base “template” (é um dos casos que temos em nosso ambiente). Neste caso, a data dos objetos não é confiável e então deveríamos considerar como “data de criação” a data em que o deploy ocorreu em produção, e aí consideramos ou a data do primeiro restore (vide restorehistory ou dbi_crdate) ou a data de deploy (que é persistida em alguns processos em tabelas de controle criadas por usuário). Na ausência da dbi_moddate talvez seja a melhor forma de chegar na data de criação, porém essa possibilidade deve ser analisada com bastante cuidado.
Vale lembrar que, dependendo da pergunta que se pretende responder, talvez a data de deploy da base em produção, se for controlada através de uma mecanismo particular pode servir para responder qual é a data de criação de uma base (e não é necessariamente a verdadeira). Imagine que uma base BDABC foi criada em 2010 em desenvolvimento e só subiu pra produção em 2013. Dependendo do caso, o “nascimento” dela pro negócio foi em 2013 quando o deploy foi feito pra ser utilizado na vera e não a data em que a base foi realmente concebida (3 anos antes). É algo a se pensar também…
Espero que o artigo tenha sido útil e fique à vontade para corrigir, comentar, opinião, críticar, etc.
[]’s
Referências
- sys.databases (Create Date) – http://msdn.microsoft.com/pt-br/library/ms178534.aspx
- Mais sobre Boot Page – http://www.sqlskills.com/blogs/paul/search-engine-qa-20-boot-pages-and-boot-page-corruption/