数据库炸了进行数据恢复的整个过程

先说下事件起因..

莫名的数据库服务器硬盘损坏,由于没做raid,只能靠过去的备份数据生活了.

由于定期备份.整个事件还算能在坑中跳出来.

数据库崩溃日期是在周五早晨.瘫痪了一个工作日,找了一个硬盘修复的外包人员做数据恢复.

然后我用过去搭建的测试库,恢复了上周的备份,并用这个备份库挺了有好一段时间.

硬盘数据基本没有找回..给服务器加了两块硬盘.做了一个raid1,算长个教训..

下面说下我后续恢复原本服务器数据的过程.

数据库基础信息

原始数据库:A库,备用数据库:B库

1.重建损坏的表空间中所对应的表

-1.将A库的损坏表空间进行下线删除 

#相关sql:

alter database datafile '/URl/NEW_DATA_CREATEDATE_2017.DBF' offline drop; 

-2.下线损坏表空间后A库可以启动

-3.查看损坏数据库表空间上存在的表信息,将表信息移动到新建的表空间中,由于表空间损坏只能将表结构创建到新的位置,表中数据查询时会报错

#相关sql:

SELECT t.table_name 表名称,t.tablespace_name 表空间名,'CREATE TABLE '|| table_name ||'_new AS SELECT * FROM '|| table_name ||' WHERE 1=2;' 创建新空表,'ALTER TABLE '|| table_name ||' RENAME TO '|| table_name ||'_old;' 将旧表更名,'ALTER TABLE '|| table_name ||'_new RENAME TO '|| table_name ||';' 将新表调整为原名,'CREATE TABLE '|| table_name ||'_new AS SELECT * FROM '|| table_name ||';' 建立拥有全部数据新表FROM User_Tables tWHEREinstr(t.tablespace_name,'NEW_DATA_CREATEDATE_2017')=1

-4.给复制新建的表结构设置主键,上述方式复制结构的表主键已经消失.

--1.删除原有的表主键,因为主键名称会存在冲突

#相关sql:

SELECT REPLACE(a.table_name, '_OLD') tablename,a.table_name,a.constraint_name,'ALTER TABLE '||a.table_name||' DROP CONSTRAINT '||a.constraint_name||';'FROM user_cons_columns a, user_constraints bWHERE a.constraint_name = b.constraint_nameAND b.constraint_type = 'P'AND instr(a.table_name, '_OLD') >= 1ORDER BY a.table_name

#遇到问题:

删除主键时,出现部分 #异常提醒:ORA-02273: this unique/primary key is referenced by some foreign keys,该主键是其他表的外键,这时候需要删除其他表相关的外键

#相关sql:

select  'alter table '||a.Table_Name||' drop constraint '||a.constraint_name||';' 删除主键关联的外键select  'alter table '||a.Table_Name||' drop constraint '||a.constraint_name||';' 删除主键关联的外键,a.table_name 外键表名,a.constraint_name 外键名,a.r_constraint_name 主键名from user_constraints A, user_constraints BWHERE b.table_name = upper('A_ASSET_OLD')and a.constraint_type = 'R'and a.r_constraint_name = b.constraint_name;

--2.给新表创建主键

#相关sql:

SELECT t.table_name 表名,c.constraint_name 主键名,'alter table '||t.table_name||' add constraint '||t.table_name||'_KEY primary key('||t.table_name||'_ID);' 创建主键,'ALTER TABLE '||t.table_name||' DROP CONSTRAINT '||c.constraint_name||';' 删除主键FROM user_tables tLEFT JOIN all_constraints c ON c.table_name=t.table_name AND c.constraint_type='P'WHERE t.tablespace_name='NEW_DATA_TABLESPACE'AND c.constraint_name IS NULL

#异常提醒:ORA-00955: name is already used by an existing object

将不能创建的索引名称做了调整,调整后创建成功

-5.给新建的表按照原有表结构创建相应的字段索引

#相关sql:

SELECT t.table_name 表名称,t.index_name 索引名称,c.column_name 字段名从,t.tablespace_name 索引表空间,t.index_type 索引类型,'DROP INDEX '||t.index_name 删除索引,'CREATE INDEX '||t.index_name||' on ' ||t.table_name||' ('||c.column_name||') TABLESPACE DATA_TABLESPACE_INDEX ' 创建字段索引FROM dba_indexes t,dba_ind_columns cWHEREt.tablespace_name='NEW_DATA_TABLESPACE_INDEX'AND t.index_name=c.index_nameORDER BY t.table_name

--1.建立索引前需要先运行生成相关规则的语句

--2.根据生成的语句先删除原本的索引

删除索引时遇到部分问题: #异常提醒:索引为主键索引,ORA-02429: cannot drop index used for enforcement of unique /primary key

处理方法:

1.将表的字段主键取消

#相关sql:

alter TABLE 表名称 DROP CONSTRAINT 主键名称;

2.将表的主键再加回去

#相关sql:

alter table 表名称 add constraint 主键名 primary key(字段名);

--3.删除原本索引后再进行新索引的生成,否则会产生重名不能创建索引

-6.给新建的表按照原有表的默认值情况添加默认值

#相关sql:

SELECT t.TABLE_NAME,t.COLUMN_NAME,t.DATA_TYPE,t.DATA_LENGTH,t.DATA_DEFAULT,'alter table '||REPLACE(TABLE_NAME,'_OLD','')||' modify '||t.COLUMN_NAME||' default '||LONG_TO_CHAR(TABLE_NAME,t.COLUMN_ID)||';'from USER_TAB_COLUMNS t where instr(upper(TABLE_NAME ),'_OLD')>=1AND t.DATA_DEFAULT IS NOT NULLAND instr(LONG_TO_CHAR(TABLE_NAME,t.COLUMN_ID),'NULL')=0

-7.删除原有表

#相关sql:

select t.table_name,t.TABLESPACE_NAME,'drop table '||t.table_name||';' 删除旧的数据表FROM User_Tables twhere instr(t.TABLE_NAME,'_OLD')>=1

-8.查看所有在损坏索引表空间上的索引,进行所有相关表字段索引的重建

#相关sql:

SELECT t.table_name 表名称,t.index_name 索引名称,c.column_name 字段名从,t.tablespace_name 索引表空间,t.index_type 索引类型,'DROP INDEX '||t.index_name 删除索引,'CREATE INDEX '||t.index_name||' on ' ||t.table_name||' ('||c.column_name||') TABLESPACE DATA_TABLESPACE_INDEX ' 创建索引   FROM dba_indexes t,dba_ind_columns c WHERE  t.tablespace_name='NEW_DATA_TABLESPACE_INDEX' AND t.index_name=c.index_name ORDER BY t.table_name​

2.删除A库中7.24日之后到8.2日之间创建的数据,

因为A库中在7.24日到8.2日直接创建创建的数据ID和B库中创建的数据ID不能对应,保留原本数据会导致数据错乱,需要将这部分数据清空,然后再将B库中数据导入到A库中

-1.获取存在更新数据的表的名称和基础信息

使用OracleDataScript.java中getAllUserTableNameList()生成需要删除和更新的数据

-2根据表名称和更新时间将相关数据全部删除

删除对应表在对应时间创建的数据​

3.将原有表空间进行删除

4.将B库中的7.24日之后创建数据导入到A库中

1.从B库中将相关表数据导入到A库中

我使用的工具是kettle因为维护的数据是部分指定日期的数据,所以比较坑.只能一个个自己手动写入操作方式:创建一个​转换,创建A,B库数据库链接,创建B库相关表的表输出,创建A库相关表的插入/更新,更新匹配字段只选择主键,更新字段为全部​kettle教程:https://www.cnblogs.com/mq0036/p/9238646.htmlkettle下载路径:链接: https://pan.baidu.com/s/1-57zbnNaLItHfiB8_TISlw 提取码: wc3d ​

#遇到问题:

数据导入过程中出现问题: #异常提醒ora01653 表空间不足

产生问题原因:oracle单个表空间文件不能超过32G达到32G后无法扩展更细致问题:oracle数据库表空间的构成数据块构成的,默认单个数据块大小为4k,个数默认为8k个,然后单个表空间默认的大小就是32G了https://www.cnblogs.com/heyanan/p/10918282.html​

处理方案:

处理办法,将表空间中数据进行拆分,拆分到不同的表空间,首先创建表空间,然后将已经满了的表空间中的数据表进行迁移

查看每个表空间的大小情况:

SELECT upper(f.tablespace_name) "表空间名",         d.tot_grootte_mb "表空间大小(M)",       d.autoextensible 是否自动扩展,       d.file_name "表空间位置",         d.tot_grootte_mb - f.total_bytes "已使用空间(M)",         to_char(round((d.tot_grootte_mb - f.total_bytes) /                       d.tot_grootte_mb * 100,                       2),                 '990.99') || '%' "使用比",         f.total_bytes "空闲空间(M)",         f.max_bytes "最大块(M)"   from (SELECT tablespace_name,                                               round(SUM(bytes) /                                                     (1024 * 1024),                                                     2) total_bytes,                                               round(MAX(bytes) /                                                     (1024 * 1024),                                                     2) max_bytes                                                                                 FROM sys.dba_free_space   group BY tablespace_name) f,          (SELECT dd.tablespace_name,                  dd.autoextensible ,file_name,                     round(SUM(dd.bytes) / (1024 * 1024), 2) tot_grootte_mb   from sys.dba_data_files dd   group BY dd.tablespace_name,                  dd.autoextensible,                  file_name) d                     where d.tablespace_name = f.tablespace_name                     order BY 1;

根据获取已经满溢的表空间后,将表空间中的表移动到新的表空间

新建新的表空间

create tablespace NEW_DATA_TABLESPACE_3  datafile    '/url/NEW_DATA_TABLESPACE_3.dbf'size 1000 m  --设置表空间初始大小autoextend on   next 50m   --设置表空间每次扩展的大小

将满溢表空间中的表移动到新建的表空间中

SELECT ut.tablespace_name 表分区名,de.block_id 数据块位置,FILE_ID 表空间位置,       table_name 表名称,       'ALTER TABLE ' || table_name ||       ' MOVE TABLESPACE NEW_DATA_TABLESPACE_2' 转移表分区的位置  FROM user_tables ut  LEFT JOIN dba_extents de ON de.segment_name = ut.table_name WHERE  ut.table_name =upper('BE_M_TRAVEL_LINE_SET')   AND ut.tablespace_name = de.tablespace_name ORDER BY 数据块位置 DESC

5.将B库中的7.24日之后更新的数据同步更新到A库中

使用kettle进行数据更新,数据转换功能


以上就是我做了数据恢复的过程..其他坑坑洼洼也不少..不过最后总算是恢复正常了.

做个记录希望不要有再用到的时候.

你可能感兴趣的:(数据库炸了进行数据恢复的整个过程)