insert引起的死锁

DEADLOCK DETECTED ( ORA-00060 )
[Transaction Deadlock]
The following deadlock is not an ORACLE error. It is a
deadlock due to user error in the design of an application
or from issuing incorrect ad-hoc SQL. The following
information may aid in determining the deadlock:
Deadlock graph:
———Blocker(s)——– ———Waiter(s)———
Resource Name process session holds waits process session holds waits
TX-000a0002-00005420 68 440 X 65 496 S
TX-0001001b-00002b19 65 496 X 68 440 S
session 440: DID 0001-0044-000A2346 session 496: DID 0001-0041-000CBA54
session 496: DID 0001-0041-000CBA54 session 440: DID 0001-0044-000A2346
Rows waited on:
Session 496: obj – rowid = 00014282 – AAAUKCAAMAAAEZrAAA
(dictionary objn – 82562, file – 12, block – 18027, slot – 0)
Session 440: no row
Information on the OTHER waiting sessions:
Session 496:
pid=65 serial=58006 audsid=1896040 user: 88/VAS
O/S info: user: web_meg, term: unknown, ospid: , machine: ezg-web1
program: JDBC Thin Client
application name: JDBC Thin Client, hash value=2546894660
Current SQL Statement:
insert into TAB_XN_CONTENT_TEMP (key,content) values (:1,:2)
End of information on OTHER waiting sessions.
Current SQL statement for this session:
insert into TAB_XN_CONTENT_TEMP (key,content) values (:1,:2)

我一看到这个错误,有点不明白,oracle 的insert操作竟然导致表被锁,然后查找些资料终于有了眉目:
当ORACLE执行insert等DML语句时,会首先自动在所要操作的表上申请一个TM锁,当TM锁获得后,再自动申请TX类型的锁。当两个或多个会话在表的同一条记录上执行DML语言时,第一个会话在记录上加锁,其它的会话处于等待状态,一直到第一个会话提交后TX锁释放,其它的会话才可以加锁。考虑是因为两个insert语句同时试图向一个表中插入PK或unique值相同的数据,而造成其中会话被阻塞,等待其它会话提交或回滚,因而造成死锁。这种情况,只要其中任何一个session提交,另外一个就会报出ORA-00001:违反唯一性约束条件,死锁终止;或者其中一个session回滚,另外一个即可正常执行。
通过对这段话的理解,应该是一个会话插入了一条记录未提交,然后另外一个会话继续插入主键或者唯一索引列相同的记录,导致死锁的发生。

环境模拟:
在会话1中执行下面语句
CREATE TABLE t1(ID NUMBER);
ALTER TABLE t1 ADD primary key (ID);
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(2);

然后在会话2中执行下面语句
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(2);

在会话3中查询死锁情况
通过上面模拟,重现了insert死锁现象,说明红色标注出来的文字的正确性

DBMS_STATS常用方法(收集oracle信息)

–收集数据库信息
EXEC DBMS_STATS.gather_database_stats;
EXEC DBMS_STATS.gather_database_stats(estimate_percent => 15);

–收集schema信息
EXEC DBMS_STATS.gather_schema_stats(‘SCOTT’);
EXEC DBMS_STATS.gather_schema_stats(‘SCOTT’, estimate_percent => 15);

–收集表信息
EXEC DBMS_STATS.gather_table_stats(‘SCOTT’, ‘EMPLOYEES’);
EXEC DBMS_STATS.gather_table_stats(‘SCOTT’, ‘EMPLOYEES’, estimate_percent => 15);

–收集index信息
EXEC DBMS_STATS.gather_index_stats(‘SCOTT’, ‘EMPLOYEES_PK’);
EXEC DBMS_STATS.gather_index_stats(‘SCOTT’, ‘EMPLOYEES_PK’, estimate_percent => 15);

–删除收集信息
EXEC DBMS_STATS.delete_database_stats;
EXEC DBMS_STATS.delete_schema_stats(‘SCOTT’);
EXEC DBMS_STATS.delete_table_stats(‘SCOTT’, ‘EMPLOYEES’);
EXEC DBMS_STATS.delete_index_stats(‘SCOTT’, ‘EMPLOYEES_PK’);

–创建备份收集信息表
begin
dbms_stats.create_stat_table(USER,stattab => ‘STAT_TABLE’);
end;

–备份收集信息
BEGIN
dbms_stats.export_table_stats(USER,tabname => ‘FEI_T’,stattab => ‘STAT_TABLE’);
END;

–删除收集信息
BEGIN
DBMS_STATS.delete_table_stats(USER,tabname => ‘FEI_T’);
END;

–导入收集信息
BEGIN
dbms_stats.IMPORT_TABLE_STATS(USER,’FEI_T’,stattab => ‘STAT_TABLE’);
END;

–说明:
当前用户可以使用user代替用户名
分析表相关对象信息cascade => true

表在线重定义(有主键)

主要是使用DBMS_REDEFINITION包实现,我这里主要是实现一个由普通表转为分区表的处理

在线重定义的表自行验证,看该表是否可以重定义
EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE(user, ‘T_DEF’, DBMS_REDEFINITION.CONS_USE_PK);
–如果T_DEF表无主键,请添加上,不然会爆如下错误
begin DBMS_REDEFINITION.CAN_REDEF_TABLE(user, ‘T_DEF’, DBMS_REDEFINITION.CONS_USE_PK); end;
ORA-12089: cannot online redefine table “CHF”.”T_DEF” with no primary key
ORA-06512: at “SYS.DBMS_REDEFINITION”, line 137
ORA-06512: at “SYS.DBMS_REDEFINITION”, line 1479
ORA-06512: at line 2

执行表的在线重定义
EXEC DBMS_REDEFINITION.START_REDEF_TABLE(USER, ‘T_DEF’, ‘T_DEF_NEW’);

同步数据
exec dbms_redefinition.sync_interim_table(USER, ‘T_DEF’, ‘T_DEF_NEW’);

执行结束在线定义过程
EXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE(user, ‘T_DEF’, ‘T_DEF_NEW’);

说明:
1、和使用交换分区的办法处理,这个是在线的,不用停业务
2、在线重定义处理后,原表中的数据不会被清空,可能需要额外的空间
3、处理速度没有直接使用交互分区快

Rman异机恢复

一、查看数据库的dbid
select dbid from v$database;

二、修改参数文件
create pfile=’/tmp/pfile’ from spfile;
直接恢复spfile

三、rman操作
1.rman target /
2.startup nomount pfile=’xxxxxx’
3.set DBID=XXXXXXX

4.恢复控制文件

run{
allocate channel c1 type disk;
restore controlfile from '控制文件rman备份路径';
release channel c1;
}

5.加载控制文件
alter database mount;

6.恢复

run{
allocate channel c1 type disk;
[Set newname for datafile 1 to '新数据文件路径';]
restore database;
[switch datafile all;]
--rman中修改控制文件中datafile path
--sql "alter database rename file ''/opt/oracle/oradata/test/xff_02.dbf'' to ''/opt/oracle/oradata/test/xifenfei02.dbf''"
recover database;
release channel c1;
}