Skip to content

Commit f2f8b6a

Browse files
committed
Add demos de corrupcao
1 parent e98203a commit f2f8b6a

17 files changed

+2663
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/*
2+
Criar um banco e gerar os dados com .\CreateDbCorrupt.sql
3+
Esse script vai gerar um backup que será usado posteriormente.
4+
Lembre-se de ajustar o caminho do backup para um local existente na sua máquina
5+
Seguir os scripts na ordem numérica.
6+
As demos são os scripts com o formato NN-Descricao.sql, onde NN é um número com 2 dígitos sempre.
7+
Scripts sem números iniciais são apenas auxiliares, referenciando nas demos ou deixados a título de curiosidade.
8+
*/
Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
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

Comments
 (0)