基于sys.fn_dblog()的SQL Server日志分析过程
2016-01-14 16:17
453 查看
在SQL Server 2005及之前的版本, 可以用Log Explorer工具来分析读取数据库日志, 但据我所知, SQL2008及之后的版本, Log Explorer工具暂时无法支持.
因此,我们可以自己开发工具来实现分析读取数据库日志的目的,大致思路如下:
1.使用系统函数sys.fn_dblog()读取原始日志信息.
2.通过系统表sys.tables,sys.columns,sys.systypes等获取表结构及数据类型.
3.调用SQL CLR(C#实现) 分析数据库日志,得到日志中每步操作对应的正向SQL(Redo)和反向SQL(Undo).
详细的实验步骤如下:
1.建测试表dbo.OrderDetail.
2. 操作1: 新增3行
3. 操作2: 更新1行
4.操作3: 更新3行
5. 操作4: 删除3行
结果如下:
此时, 目标表已为空, 接下来, 我们通过系统函数sys.fn_dblog()和调用SQL CLR来实现在线恢复.
恢复步骤如下:
1. 分析查询日志, 得到反向操作SQL序列.
执行结果:
得到正向SQL(Redo)和反向SQL(Undo),
2.复制出所有反向SQL, 即结果中的UndoSQL列. 因结果是按时间倒序排列, 因此顺序刚好与之前的操作顺序相反, 便于恢复操作.
3.恢复各个操作.
执行结果, 即回到原操作1之后的结果, 恢复完成!
因此,我们可以自己开发工具来实现分析读取数据库日志的目的,大致思路如下:
1.使用系统函数sys.fn_dblog()读取原始日志信息.
2.通过系统表sys.tables,sys.columns,sys.systypes等获取表结构及数据类型.
3.调用SQL CLR(C#实现) 分析数据库日志,得到日志中每步操作对应的正向SQL(Redo)和反向SQL(Undo).
详细的实验步骤如下:
1.建测试表dbo.OrderDetail.
create table dbo.OrderDetail (OrderID int not null, ItemID int not null, ItemNumber varchar(10), QTY int, Price decimal(8,2), ADate date, AUser char(20), UDate datetime, UUser varchar(20) constraint pk_OrderDetail primary key(OrderID,ItemID) )
2. 操作1: 新增3行
-- 操作1: 新增3行 insert into dbo.OrderDetail(OrderID,ItemID,ItemNumber,QTY,Price,ADate,AUser,UDate,UUser) select 1001,1,'D001',100,45.62,'2015-01-02','Xh6','2015-01-03 20:15:18','Lx4' union all select 1001,2,'Z001_2',150,180,'2015-01-02','cx5','2015-01-08 02:45:32','Yx3' union all select 1002,1,'Z001_2',300,182.07,'2015-12-12','CL1','2015-12-18 02:45:32','LY6' select * from dbo.OrderDetail结果如下:
3. 操作2: 更新1行
-- 操作2: 更新1行 update dbo.OrderDetail set QTY=999 where OrderID=1001 and ItemID=1 select * from dbo.OrderDetail结果如下:
4.操作3: 更新3行
-- 操作3: 更新3行 update dbo.OrderDetail set ItemNumber='!@#$%' select * from dbo.OrderDetail结果如下:
5. 操作4: 删除3行
-- 操作4: 删除3行 delete from dbo.OrderDetail select * from dbo.OrderDetail
结果如下:
此时, 目标表已为空, 接下来, 我们通过系统函数sys.fn_dblog()和调用SQL CLR来实现在线恢复.
恢复步骤如下:
1. 分析查询日志, 得到反向操作SQL序列.
exec dbo.DBA_ReadDatabaseLog @startTime='2016-01-14 00:00:00', -- 开始时间 @endTime='2016-01-31 23:59:59', -- 结束时间 @objectName='dbo.OrderDetail', -- 表名 @sorttype='DESC' -- 日志排序方式(升序/降序)
执行结果:
得到正向SQL(Redo)和反向SQL(Undo),
2.复制出所有反向SQL, 即结果中的UndoSQL列. 因结果是按时间倒序排列, 因此顺序刚好与之前的操作顺序相反, 便于恢复操作.
3.恢复各个操作.
-- 恢复原操作4(删除3行) insert into dbo.OrderDetail([OrderID],[ItemID],[ItemNumber],[QTY],[Price],[ADate],[AUser],[UDate],[UUser]) values(1002, 1, '!@#$%', 300, 182.07, '2015-12-12', 'CL1', '2015-12-18 02:45:32.000', 'LY6'); insert into dbo.OrderDetail([OrderID],[ItemID],[ItemNumber],[QTY],[Price],[ADate],[AUser],[UDate],[UUser]) values(1001, 2, '!@#$%', 150, 180.00, '2015-01-02', 'cx5', '2015-01-08 02:45:32.000', 'Yx3'); insert into dbo.OrderDetail([OrderID],[ItemID],[ItemNumber],[QTY],[Price],[ADate],[AUser],[UDate],[UUser]) values(1001, 1, '!@#$%', 999, 45.62, '2015-01-02', 'Xh6', '2015-01-03 20:15:18.000', 'Lx4'); -- 恢复原操作3(更新3行) update dbo.OrderDetail set [ItemNumber]='Z001_2' where [OrderID]=1002 and [ItemID]=1 update dbo.OrderDetail set [ItemNumber]='Z001_2' where [OrderID]=1001 and [ItemID]=2 update dbo.OrderDetail set [ItemNumber]='D001' where [OrderID]=1001 and [ItemID]=1 -- 恢复原操作2(更新1行) update dbo.OrderDetail set [QTY]=100 where [OrderID]=1001 and [ItemID]=1
select * from dbo.OrderDetail
执行结果, 即回到原操作1之后的结果, 恢复完成!
相关文章推荐
- SQL Where特殊的三个条件(between,in,like(字符串匹配,模糊查寻))
- java对redis的基本操作
- PLSQL使用IP地址连接远程服务器
- 对已经发布订阅的sqlserver进行修改-添加新的表
- 优化SQL语句,提高数据库的访问性能
- 【SQL 编程你也行】SQL Server新功能之函数:sum函数(2005、2008、2012、2014)
- Host 'xx.xx.xxx.xxx' is not allowed to connect to this MySQL server
- LDAP是什么?LDAP与数据库有什么区别?
- C#中大批量导入数据SqlBulkCopy
- EXP-00000: Message 0 not found; No message file for product=RDBMS, facility=EXP问题的解决方案
- oracle中的wm_concat函数以及over分析函数
- 安装oracle10g
- postgresql 的三类日志
- mysql把一张表里的数据插入到另一张表里
- Excel数据导入sql server数据表
- sqlserver 建立索引视图各问题!
- oracle中在同一个表中分类查询不同类型的前几条数据
- oracle学习
- 设置mysql日志输出路径的方法
- <转>windows下安装redis