1+ /* *
2+ DEMO
3+ Cenários de corrupção
4+ Objetivo
5+ Mostrar as várias formas como uma corrupção pode se apresentar
6+
7+ Autores:
8+ Gustavo Maia Aguiar
9+ Rodrigo Ribeiro Gomes
10+ **/
11+
12+
13+
14+ -- Restaurando a base ORIGINAL!!
15+ USE master
16+ GO
17+
18+ IF OBJECT_ID (' tempdb..spRestore' ) IS NOT NULL
19+ EXEC (' DROP PROC spRestore' )
20+ GO
21+
22+ CREATE PROC spRestore
23+ AS
24+ IF DB_ID (' DbCorrupt' ) IS NOT NULL
25+ BEGIN
26+ EXEC (' ALTER DATABASE DbCorrupt SET READ_WRITE WITH ROLLBACK IMMEDIATE' )
27+ EXEC (' ALTER DATABASE DbCorrupt SET READ_ONLY WITH ROLLBACK IMMEDIATE' )
28+ EXEC (' DROP DATABASE DbCorrupt' )
29+ END
30+
31+ RESTORE DATABASE DBCorrupt
32+ FROM DISK = ' T:\DbCorrupt.bak'
33+ WITH
34+ REPLACE
35+ ,STATS = 10
36+ -- ,MOVE 'DBCorrupt' TO 'C:\temp\DBCorrupt.mdf'
37+ -- ,MOVE 'DBCorrupt_log' TO 'C:\temp\DBCorrupt.ldf'
38+
39+ -- Base em recovery SIMPLE!
40+ ALTER DATABASE DBCorrupt SET RECOVERY SIMPLE ; -- Neste cenário o RECOVERY MODEL não interfere... tanto faz... vou deixar no simple, que é o mais restritivo!
41+ GO
42+
43+ USE master ;
44+ EXEC spRestore;
45+ USE DBCorrupt
46+ GO
47+
48+
49+
50+ -- Checksum em páginas de dados
51+ ALTER DATABASE DBCorrupt SET PAGE_VERIFY CHECKSUM -- Padrão 2008+
52+
53+ -- confirmando que tudo ok
54+ select top 1
55+ *
56+ from
57+ dbo .Lancamentos
58+ order by
59+ DataLancamento
60+
61+ -- vamos corromper a primeira página!
62+ SELECT top 10 P .allocated_page_page_id ,P .page_level
63+ ,P .previous_page_page_id ,P .next_page_page_id
64+ ,p .page_type_desc ,p .extent_page_id
65+ FROM
66+ DBCorrupt .sys .dm_db_database_page_allocations(
67+ DB_ID (' DBCorrupt' )
68+ ,OBJECT_ID (' DBCorrupt.dbo.Lancamentos' )
69+ ,1
70+ ,NULL
71+ ,' DETAILED'
72+ ) P
73+ WHERE P .page_level = 0 and p .page_type_desc = ' DATA_PAGE'
74+ ORDER BY p .allocated_page_page_id
75+
76+ -- write page!
77+ ALTER DATABASE DBCorrupt SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
78+ -- dbcc traceon(2588) dbcc tracestatus
79+ -- dbcc help('writepage')
80+ -- banco,file,pagina,start,length,data,direct
81+ DBCC WRITEPAGE(' DBCorrupt' ,1 ,360 ,0 ,2 ,0x1234,1 ) -- direct = nao calcula checsum
82+ ALTER DATABASE DBCorrupt SET MULTI_USER WITH ROLLBACK IMMEDIATE ;
83+
84+ -- vamos ler
85+ select top 1
86+ *
87+ from
88+ dbo .Lancamentos
89+ order by
90+ DataLancamento
91+
92+ -- como contornar?
93+ ALTER DATABASE DBCorrupt SET PAGE_VERIFY none
94+
95+ -- TENTA NOVAMENTE acima
96+
97+
98+
99+ -- volta pro checksum
100+ ALTER DATABASE DBCorrupt SET PAGE_VERIFY checksum
101+
102+ -- tenta novamente...
103+ -- deu? agora:
104+ checkpoint ; dbcc dropcleanbuffers
105+
106+ -- tenta novamente
107+ -- checksum só é verificado quando é lida do disco!
108+
109+
110+ -- campos com valores incorretos pageId (Será que checksum resolve?)
111+
112+ -- restaurar o banco de novo...
113+ USE master ;
114+ EXEC spRestore;
115+ USE DBCorrupt
116+ GO
117+
118+
119+ -- mostrar o campo m_PageId
120+ DBCC TRACEON(3604 )
121+ DBCC PAGE (' DBCorrupt' ,1 ,360 ,2 ) with tableresults
122+
123+
124+ -- m_NextPage = (0:0)
125+ ALTER DATABASE DBCorrupt SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
126+ DBCC WRITEPAGE(' DBCorrupt' ,1 ,360 ,' m_pageId' ,6 ,0x000000000000,0 ) -- via bpool, pro checksum ficar ok.
127+ ALTER DATABASE DBCorrupt SET MULTI_USER WITH ROLLBACK IMMEDIATE ;
128+
129+ -- alterou? ParentObject = PAGE HADER , Field = m_PageId
130+ DBCC PAGE (' DBCorrupt' ,1 ,360 ,2 ) with tableresults
131+
132+ -- vamos ler
133+ -- SE TIVER NORMAL: checkpoint; dbcc dropcleanbuffers
134+ select top 1
135+ *
136+ from
137+ dbo .Lancamentos
138+ order by
139+ DataLancamento
140+
141+
142+
143+
144+
145+ -- desligar o page_verify
146+ -- como contornar?
147+ ALTER DATABASE DBCorrupt SET PAGE_VERIFY none
148+ -- resolve?
149+
150+ -- volta
151+ ALTER DATABASE DBCorrupt SET PAGE_VERIFY checksum
152+
153+
154+
155+ -- checkdb
156+ dbcc checkdb(DbCorrupt)
157+ dbcc checktable(Lancamentos)
158+ dbcc checkdb(DbCorrupt) with physical_only
159+ dbcc checktable(Lancamentos) with physical_only
160+
161+
162+
163+ -- fix
164+ ALTER DATABASE DBCorrupt SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
165+ DBCC CHECKTABLE(Lancamentos,REPAIR_REBUILD)
166+ ALTER DATABASE DBCorrupt SET MULTI_USER WITH ROLLBACK IMMEDIATE ;
167+
168+
169+
170+ -- allow data loss
171+ ALTER DATABASE DBCorrupt SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
172+ DBCC CHECKTABLE(Lancamentos,REPAIR_allow_data_loss)
173+ ALTER DATABASE DBCorrupt SET MULTI_USER WITH ROLLBACK IMMEDIATE ;
174+
175+ -- vamos ler (perdeu algo??)
176+ select top 1
177+ *
178+ from
179+ dbo .Lancamentos
180+ order by
181+ DataLancamento
182+
183+ -- header zerado! (Será que checksum resolve?)
184+
185+ -- restaurar o banco de novo...
186+ USE master ;
187+ EXEC spRestore;
188+ USE DBCorrupt
189+ GO
190+
191+ DBCC TRACEON(3604 )
192+ DBCC PAGE (' DBCorrupt' ,1 ,360 ,2 ) with tableresults
193+
194+ -- vamos corromper o header!
195+ declare @sql nvarchar (max )
196+ declare @bin varchar (max ) = convert (varchar (max ),convert (varbinary (96 ),replicate (0x00,96 )),1 )
197+ set @sql = ' DBCC WRITEPAGE('' DBCorrupt'' ,1,360,0,96,'+ @bin+ ' ,0)'
198+ print (@sql)
199+ ALTER DATABASE DBCorrupt SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
200+ exec (@sql)
201+ ALTER DATABASE DBCorrupt SET MULTI_USER WITH ROLLBACK IMMEDIATE ;
202+
203+ -- tabela voltou? repare o id!
204+ select top 1 * from Lancamentos
205+
206+ -- resolve?
207+ ALTER DATABASE DBCorrupt SET PAGE_VERIFY none
208+ -- volta
209+ ALTER DATABASE DBCorrupt SET PAGE_VERIFY checksum
210+
211+ -- allow data loss
212+ ALTER DATABASE DBCorrupt SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
213+ DBCC CHECKTABLE(Lancamentos,REPAIR_allow_data_loss)
214+ ALTER DATABASE DBCorrupt SET MULTI_USER WITH ROLLBACK IMMEDIATE ;
215+
216+
217+ -- campos com valores incorretos (next page) (PODE SER BEM DIFÍCIL DETECTAR E RESOLVER ESSA)
218+
219+ -- restaurar o banco de novo...
220+ USE master ;
221+ EXEC spRestore;
222+ USE DBCorrupt
223+ GO
224+
225+
226+ DBCC TRACEON(3604 )
227+ DBCC PAGE (' DBCorrupt' ,1 ,360 ,0 ) with tableresults
228+
229+
230+ -- m_NextPage = (0:0)
231+ ALTER DATABASE DBCorrupt SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
232+ DBCC WRITEPAGE(' DBCorrupt' ,1 ,360 ,' m_nextPage' ,6 ,0x000000000000,2 ) -- via bpool, pro checksum ficar ok.
233+ ALTER DATABASE DBCorrupt SET MULTI_USER WITH ROLLBACK IMMEDIATE ;
234+
235+
236+
237+ -- quantas linhas tem?
238+ select count (* ) from dbo .Lancamentos
239+
240+ -- será mesmo?
241+ select * from Lancamentos
242+
243+
244+ --
245+ select count (* ) from Lancamentos with (index (0 ))
246+
247+ select count (* ) from lancamentos with (index (0 )) option (maxdop 1 )
248+
249+
250+ -- como pega? (por isso importancia disso rodar periodicamente)
251+ DBCC CHECKDB(' DbCorrupt' )
252+ DBCC CHECKTABLE(Lancamentos)
253+ DBCC CHECKTABLE(Lancamentos) with physical_only -- ops
254+ DBCC CHECKDB(' DbCorrupt' ) with physical_only -- ops
255+
256+
257+ -- repair funciona?
258+ ALTER DATABASE DBCorrupt SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
259+ DBCC CHECKTABLE(Lancamentos,REPAIR_REBUILD)
260+ ALTER DATABASE DBCorrupt SET MULTI_USER WITH ROLLBACK IMMEDIATE ;
261+
262+ -- repetir os count após isso...
263+
264+ -- campos com valores incorretos (pagina ida e volta) (MAIS DIFICIL DE ACONTECER)
265+
266+ -- restaurar o banco de novo...
267+ USE master ;
268+ EXEC spRestore;
269+ USE DBCorrupt
270+ GO
271+
272+ -- pegar as 2 primeiras (linkadas uma com a outra)
273+ SELECT top 5 P .allocated_page_page_id ,P .previous_page_page_id ,P .page_level
274+ ,P .previous_page_page_id ,P .next_page_page_id
275+ ,p .page_type_desc ,p .extent_page_id
276+ FROM
277+ DBCorrupt .sys .dm_db_database_page_allocations(
278+ DB_ID (' DBCorrupt' )
279+ ,OBJECT_ID (' DBCorrupt.dbo.Lancamentos' )
280+ ,1
281+ ,NULL
282+ ,' DETAILED'
283+ ) P
284+ WHERE P .page_level = 0 and p .page_type_desc = ' DATA_PAGE'
285+ ORDER BY p .allocated_page_page_id
286+
287+ -- vamos zerar o NextPage e o PrevPage da proxima! Em tese, isso não gera incosistencias.
288+ ALTER DATABASE DBCorrupt SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
289+ DBCC WRITEPAGE(' DBCorrupt' ,1 ,360 ,' m_nextPage' ,6 ,0x000000000000,2 ) -- via bpool, pro checksum ficar ok.
290+ DBCC WRITEPAGE(' DBCorrupt' ,1 ,376 ,' m_prevPage' ,6 ,0x000000000000,2 ) -- via bpool, pro checksum ficar ok
291+ ALTER DATABASE DBCorrupt SET MULTI_USER WITH ROLLBACK IMMEDIATE ;
292+
293+
294+ -- primeira pagina
295+ select * ,sys .fn_PhysLocFormatter (%%physloc%%) from Lancamentos
296+ select count (* ) from Lancamentos with (index (0 )) option (maxdop 1 )
297+
298+ -- quem estava na segunda (ver ultimo slot)?
299+ DBCC PAGE (' DBCorrupt' ,1 ,376 ,3 ) with tableresults
300+
301+ -- segunda pagina
302+ select *
303+ ,sys .fn_PhysLocFormatter (%%physloc%%)
304+ from Lancamentos where DataLancamento <= ' 20150101' and NumConta <= 10341
305+ order by DataLancamento desc , NumConta DESC
306+
307+
308+
309+ -- checktable vai pegar?
310+ DBCC CHECKTABLE(Lancamentos)
311+
312+ -- e se tentar estragar mais ainda?
313+ DBCC PAGE (' DBCorrupt' ,1 ,368 ,3 )
314+ -- offset 2
315+ DBCC PAGE (' DBCorrupt' ,1 ,368 ,2 ) with tableresults
316+
317+
318+ -- vamos tentar zerar...
319+ ALTER DATABASE DBCorrupt SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
320+ DBCC WRITEPAGE(' DBCorrupt' ,1 ,368 ,8188 ,2 ,0x0000,2 ) -- via bpool, pro checksum ficar ok.
321+ ALTER DATABASE DBCorrupt SET MULTI_USER WITH ROLLBACK IMMEDIATE ;
322+
323+
324+
325+
326+ -- xi...
327+ -- agora ficou bem ruim rsrs
328+ DBCC CHECKTABLE(Lancamentos)
329+
330+ -- repair funciona?
331+ ALTER DATABASE DBCorrupt SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
332+ DBCC CHECKTABLE(Lancamentos, repair_rebuild)
333+ ALTER DATABASE DBCorrupt SET MULTI_USER WITH ROLLBACK IMMEDIATE ;
334+
335+ -- repair funciona?
336+ ALTER DATABASE DBCorrupt SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
337+ DBCC CHECKTABLE(Lancamentos, repair_allow_data_loss)
338+ ALTER DATABASE DBCorrupt SET MULTI_USER WITH ROLLBACK IMMEDIATE ;
339+
340+ select top 500 * from Lancamentos
341+
342+ -- nao vamos continuar, pq ai fica bem compelxo e acho ser bem mais dificil acontecer esse cenario.
343+
344+
345+
346+
347+
0 commit comments