{"id":1355,"date":"2020-04-06T09:40:13","date_gmt":"2020-04-06T12:40:13","guid":{"rendered":"http:\/\/thesqltimes.com\/blog\/?p=1355"},"modified":"2020-04-27T09:11:50","modified_gmt":"2020-04-27T12:11:50","slug":"recuperar-delete-sem-backup-full-1","status":"publish","type":"post","link":"https:\/\/thesqltimes.com\/blog\/2020\/04\/06\/recuperar-delete-sem-backup-full-1\/","title":{"rendered":"Recuperando dados deletados do SQL Server sem Backup Full &#8211; Parte 1"},"content":{"rendered":"<div class=\"pld-like-dislike-wrap pld-template-1\">\r\n    <div class=\"pld-like-wrap  pld-common-wrap\">\r\n    <a href=\"javascript:void(0)\" class=\"pld-like-trigger pld-like-dislike-trigger  \" title=\"Muito \u00fatil!\" data-post-id=\"1355\" data-trigger-type=\"like\" data-restriction=\"cookie\" data-already-liked=\"0\">\r\n                        <i class=\"fas fa-thumbs-up\"><\/i>\r\n                <\/a>\r\n    <span class=\"pld-like-count-wrap pld-count-wrap\">    <\/span>\r\n<\/div><\/div><div class=\"seriesmeta\">Post 1\/6. Este post \u00e9 parte da s\u00e9rie: <a href=\"https:\/\/thesqltimes.com\/blog\/series\/recuperando-dados-deletados-sem-backup-full\/\" class=\"series-294\" title=\"Recuperando dados deletados sem Backup Full\">Recuperando dados deletados sem Backup Full<\/a>\r\n<\/div>\r\n<span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Tempo de Leitura:<\/span> <span class=\"rt-time\"> 4<\/span> <span class=\"rt-label rt-postfix\">minutos<\/span><\/span><p>N\u00e3o \u00e9 de hoje que eu me deparo com situa\u00e7\u00f5es onde h\u00e1 uma necessidade de recupera\u00e7\u00e3o de dados e n\u00e3o h\u00e1 backup FULL. N\u00e3o existe uma receita de bolo pra isso. Voc\u00ea precisa ter cartas na manga e analisar cada situa\u00e7\u00e3o.<\/p>\n<p>Nesta s\u00e9rie eu vou mostrar uma das minhas cartas para essa situa\u00e7\u00e3o:<\/p>\n<blockquote>\n<p style=\"text-align: left;\">Deletei dados usando o comando DELETE FROM sem querer! E n\u00e3o tenho backup FULL! O que eu fa\u00e7o?<\/p>\n<\/blockquote>\n<p>Tudo que eu vou falar aqui j\u00e1 foi aplicado pelo menos duas vezes por mim em cen\u00e1rios de produ\u00e7\u00e3o.<\/p>\n[stextbox id=&#8221;warning&#8221;]<strong>E cabe aqui ressaltar:<\/strong> Em todas as t\u00e9cnicas que irei mostrar, eu sabia exatamente o que estava fazendo e apliquei muita teoria! Portanto, sempre fa\u00e7a por sua conta e risco. Al\u00e9m disso, tudo isso se aplica em um ambiente SEM COMPRESS\u00c3O de linha, ou de p\u00e1gina, do SQL Server. Por isso, tenha aten\u00e7\u00e3o![\/stextbox]\n<p>Irei mostrar algumas t\u00e9cnicas que dependem de um conhecimento s\u00f3lido do internals do SQL Server, especialmente, estes assuntos:<\/p>\n<ul>\n<li><strong>Anatomia de um registro<\/strong><br \/>\nE \u00e9 claro que a melhor refer\u00eancia para este assunto \u00e9 o Paul Randal, que al\u00e9m do <a href=\"https:\/\/www.oreilly.com\/library\/view\/microsoft-sql-server\/9780735670174\/\">SQL Server Internals<\/a>, um livro que recomendo muito, v<a href=\"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-anatomy-of-a-record\/\">oc\u00ea pode conferir neste post TOP que ele fez pra explicar<\/a>! Pra quem n\u00e3o conhece ele, ele s\u00f3 foi quem escreveu diversas partes do SQL Server&#8230;<\/li>\n<li><strong>Arquitetura B\u00e1sica do Log de Transa\u00e7\u00e3o e Recovery Model<\/strong><br \/>\nAqui, <a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/relational-databases\/sql-server-transaction-log-architecture-and-management-guide?view=sql-server-ver15\">siga com a documenta\u00e7\u00e3o oficial para aprender mais<\/a>.<\/li>\n<li><strong>Internals do Log de Transa\u00e7\u00e3o<\/strong><br \/>\nEste voc\u00ea vai encontrar uma gama muito boa de detalhes <a href=\"https:\/\/www.sqlskills.com\/blogs\/paul\/category\/transaction-log\/\">nos posts do Paul Randal tamb\u00e9m<\/a>, al\u00e9m de um cap\u00edtulo s\u00f3 de log de transa\u00e7\u00e3o no livro do SQL Server Internals.<\/li>\n<\/ul>\n<p>Os testes foram realizados em um SQL Server 2017, mas para as vers\u00f5es anteriores, o procedimento \u00e9 o mesmo. Caso eu note alguma peculiaridade, eu irei avisar.<\/p>\n<p>Dito as premissas, vamos iniciar explicando o cen\u00e1rio e preparar o ambiente de testes&#8230;<\/p>\n<p><strong>O cen\u00e1rio<\/strong><\/p>\n<p>A situa\u00e7\u00e3o era a seguinte: Algu\u00e9m deletou alguns registros de uma tabela importante por volta das 16h25. N\u00e3o tinha Backup Full, e nem os logs anteriores a este FULL (eles foram apagados incorretamente). Os backups de logs estavam sendo feitos normalmente a cada 10 minutos.<\/p>\n<figure id=\"attachment_1361\" aria-describedby=\"caption-attachment-1361\" style=\"width: 913px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a276fed26c.png\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-1361 size-full\" src=\"http:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a276fed26c.png\" alt=\"\" width=\"913\" height=\"271\" srcset=\"https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a276fed26c.png 913w, https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a276fed26c-300x89.png 300w, https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a276fed26c-768x228.png 768w\" sizes=\"auto, (max-width: 913px) 100vw, 913px\" \/><\/a><figcaption id=\"caption-attachment-1361\" class=\"wp-caption-text\"><em>Se eu tivesse o backup FULL, era f\u00e1cil! Era s\u00f3 restaurar FULL + logs at\u00e9 as 16h24 e pegar os dados!<\/em><\/figcaption><\/figure>\n<p>Voc\u00ea pode utilizar <a href=\"https:\/\/github.com\/rrg92\/thesqltimes\/blob\/master\/recuperar-delete-sem-backup-full\/EstruturaTeste.sql\">este script para criar uma estrutura de teste<\/a>, inserir 10 mil linhas em uma tabela de testes com diversos dados aleat\u00f3rios, &#8220;perder&#8221; o backup full e fazer um backup de log (que tamb\u00e9m n\u00e3o \u00e9 necess\u00e1rio).<\/p>\n<p>Ent\u00e3o suponha que seja 16h25 e algu\u00e9m tenha deletado todos os 10 mil registros:<\/p>\n<p>&nbsp;<\/p>\n<p id=\"qCIbceL\"><img loading=\"lazy\" decoding=\"async\" width=\"362\" height=\"71\" class=\"alignnone size-full wp-image-1364 \" src=\"http:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a36a8b9342.png\" alt=\"\" srcset=\"https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a36a8b9342.png 362w, https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a36a8b9342-300x59.png 300w\" sizes=\"auto, (max-width: 362px) 100vw, 362px\" \/><\/p>\n<p>E suponha, que 5 minutos depois o backup de log tenha sido executado pelas rotinas:<\/p>\n<p id=\"HkZXMQa\"><img loading=\"lazy\" decoding=\"async\" width=\"808\" height=\"76\" class=\"alignnone size-full wp-image-1365 \" src=\"http:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a37142d055.png\" alt=\"\" srcset=\"https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a37142d055.png 808w, https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a37142d055-300x28.png 300w, https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a37142d055-768x72.png 768w\" sizes=\"auto, (max-width: 808px) 100vw, 808px\" \/><\/p>\n<p>Foi exatamente o que ocorreu!\u00a0 A diferen\u00e7a foi que at\u00e9 que essa situa\u00e7\u00e3o chegasse at\u00e9 mim, j\u00e1 tinha se passado horas. Ent\u00e3o, j\u00e1 haviam muitos outros backups. Ap\u00f3s descobrir o hor\u00e1rio em que foi feito eu determinei o backup correto e copiei ele para outro local para que eu pudesse iniciar as tentativas. No nosso cen\u00e1rio de exemplo, vou utilizar o pr\u00f3prio arquivo <strong>T:\\Backup16h30.trn<\/strong><\/p>\n<p><strong>E por que este backup de log?<\/strong> Ora, como o banco est\u00e1 em Recovery FULL, O SQL Server sempre loga cada linha deletada no log de transa\u00e7\u00f5es, gerando &#8220;Log Records&#8221; que cont\u00e9m os dados dessa linha. E ainda, ainda devido ao recovery model, ele s\u00f3 vai liberar ou reusar este espa\u00e7o, quando um backup de log destes registros forem feitos. Ou seja, no pr\u00f3ximo backup de log!<\/p>\n<p>OK, voc\u00ea tem o arquivo! E agora!?\u00a0 O backup de log \u00e9 um arquivo bin\u00e1rio, se abrir, mesmo num editor hexadecimal, as coisas n\u00e3o fazem muito sentido:<\/p>\n<p><a href=\"http:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a37cd76ba8.png\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-1366\" src=\"http:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a37cd76ba8.png\" alt=\"Abrindo o backup de log em um editor de texto\" width=\"704\" height=\"498\" srcset=\"https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a37cd76ba8.png 1400w, https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a37cd76ba8-300x212.png 300w, https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a37cd76ba8-1024x724.png 1024w, https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a37cd76ba8-768x543.png 768w\" sizes=\"auto, (max-width: 704px) 100vw, 704px\" \/><\/a><\/p>\n<p>E a\u00ed \u00e9 que entra a nossa primeira arma secreta: <strong>fn_dump_dblog<\/strong>. E advinha onde eu aprendi h\u00e1 muito tempo sobre ela? Isso mesmo, <a href=\"https:\/\/www.sqlskills.com\/blogs\/paul\/using-fn_dblog-fn_dump_dblog-and-restoring-with-stopbeforemark-to-an-lsn\/\">neste post do Paul Randal<\/a>!<\/p>\n<p>Basicamente, esta fun\u00e7\u00e3o me permite especificar um arquivo de backup de log, e ent\u00e3o ela monta em um resultset com toda a estrutura do log de transa\u00e7\u00e3o. Uma linha para cada &#8220;Log Record&#8221;. Tem uma fun\u00e7\u00e3o que faz a mesma coisa, a <strong>fn_dblog<\/strong>, s\u00f3 que ao inv\u00e9s de pegar do backup, ela pega do log atual do banco em que voc\u00ea est\u00e1 conectado.<\/p>\n<p><span style=\"color: #ff0000;\"><strong>ATEN\u00c7\u00c3O: Tenha cuidado! Esta fun\u00e7\u00e3o vai ler todo o backup de log! Isto \u00e9, ela pode trazer centenas de milhares de linhas.<\/strong><\/span><\/p>\n<pre class=\"lang:tsql decode:true\" title=\"Lendo um arquivo de backup de log\" data-url=\"https:\/\/raw.githubusercontent.com\/rrg92\/thesqltimes\/master\/recuperar-delete-sem-backup-full\/fn_dump_dblog.sql\">USE TheSqlTimes\nGO\n\nSELECT\n   *\nFROM\n    fn_dump_dblog (\n        NULL, NULL, N'DISK', 1, N'T:\\Backup16h30.trn',\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT);<\/pre>\n<p>A sintaxe \u00e9 auto explicativa, bem como boa parte das colunas. Voc\u00ea precisa apenas trocar o caminho. Os detalhes, deixo com as refer\u00eancias que coloquei.<\/p>\n<p id=\"xqBFDpC\"><img loading=\"lazy\" decoding=\"async\" width=\"1840\" height=\"840\" class=\"alignnone size-full wp-image-1368 \" src=\"http:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a393597190.png\" alt=\"\" srcset=\"https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a393597190.png 1840w, https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a393597190-300x137.png 300w, https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a393597190-1024x467.png 1024w, https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a393597190-768x351.png 768w, https:\/\/thesqltimes.com\/blog\/wp-content\/uploads\/2020\/04\/img_5e8a393597190-1536x701.png 1536w\" sizes=\"auto, (max-width: 1840px) 100vw, 1840px\" \/><\/p>\n<p><strong>O Paul Randal adverte sobre o uso destas duas fun\u00e7\u00f5es em seus posts. Antes de us\u00e1-las, entenda estes riscos!<\/strong><\/p>\n<p>Agora que voc\u00ea tem o log em uma estrutura que j\u00e1 \u00e9 acostumado a usar (ou deveria ser), superamos o primeiro obst\u00e1culo! No pr\u00f3ximo post, eu conto como podemos seguir a partir da\u00ed!<\/p>\n<p>Fontes e links \u00fateis:<\/p>\n<ul>\n<li>Inside the Storage Engine: Anatomy of a record<br \/>\n<a href=\"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-anatomy-of-a-record\/\">https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-anatomy-of-a-record\/<\/a><\/li>\n<li>Transaction Log Architecture and Internals (Documenta\u00e7\u00e3o oficial, em ingl\u00eas)<br \/>\n<a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/relational-databases\/sql-server-transaction-log-architecture-and-management-guide?view=sql-server-ver15\">https:\/\/docs.microsoft.com\/en-us\/sql\/relational-databases\/sql-server-transaction-log-architecture-and-management-guide?view=sql-server-ver15<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<div class=\"seriesmeta\">This entry is part 1 of 6 in the series <a href=\"https:\/\/thesqltimes.com\/blog\/series\/recuperando-dados-deletados-sem-backup-full\/\" class=\"series-294\" title=\"Recuperando dados deletados sem Backup Full\">Recuperando dados deletados sem Backup Full<\/a><\/div><p>N\u00e3o \u00e9 de hoje que eu me deparo com situa\u00e7\u00f5es onde h\u00e1 uma necessidade de recupera\u00e7\u00e3o de dados e n\u00e3o h\u00e1 backup FULL. N\u00e3o existe uma receita de bolo pra isso. Voc\u00ea precisa ter cartas na manga e analisar cada situa\u00e7\u00e3o. Nesta s\u00e9rie eu vou mostrar uma das minhas cartas para essa situa\u00e7\u00e3o: Deletei dados&hellip;&nbsp;<a href=\"https:\/\/thesqltimes.com\/blog\/2020\/04\/06\/recuperar-delete-sem-backup-full-1\/\" rel=\"bookmark\"><span class=\"screen-reader-text\">Recuperando dados deletados do SQL Server sem Backup Full &#8211; Parte 1<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":1360,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","footnotes":""},"categories":[8,3,296,295,7],"tags":[174,299,297,300,301,303,298,73,302],"series":[294],"class_list":["post-1355","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administracao","category-banco-de-dados-2","category-internals","category-recuperacao-de-dados","category-sql-server","tag-backup","tag-dados","tag-data-recovery","tag-delete-from","tag-fn_dump_dblog","tag-log","tag-recuperacao","tag-sql-server","tag-transaction-log","series-recuperando-dados-deletados-sem-backup-full"],"_links":{"self":[{"href":"https:\/\/thesqltimes.com\/blog\/wp-json\/wp\/v2\/posts\/1355","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thesqltimes.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thesqltimes.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thesqltimes.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/thesqltimes.com\/blog\/wp-json\/wp\/v2\/comments?post=1355"}],"version-history":[{"count":12,"href":"https:\/\/thesqltimes.com\/blog\/wp-json\/wp\/v2\/posts\/1355\/revisions"}],"predecessor-version":[{"id":1393,"href":"https:\/\/thesqltimes.com\/blog\/wp-json\/wp\/v2\/posts\/1355\/revisions\/1393"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/thesqltimes.com\/blog\/wp-json\/wp\/v2\/media\/1360"}],"wp:attachment":[{"href":"https:\/\/thesqltimes.com\/blog\/wp-json\/wp\/v2\/media?parent=1355"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thesqltimes.com\/blog\/wp-json\/wp\/v2\/categories?post=1355"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thesqltimes.com\/blog\/wp-json\/wp\/v2\/tags?post=1355"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/thesqltimes.com\/blog\/wp-json\/wp\/v2\/series?post=1355"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}