设想一下以下场景:
在一张大表,可能有上亿条数据,在表中建立了主键或者唯一索引。当有会话插入数据违反唯一性约束时,Oracle是如何快速判断这个值已存在,而抛出ora-00001错误呢?
从性能上来讲,Oracle不太可能将这些数据存放在shared_pool或者其他内存区域中,假如放在内存区域中,必须先解决两个问题:
1、如果有上千个唯一约束表格,在内存中遍历上千表格的数据是不现实的,那性能问题怎么解决?
2、数据库刚启动时,Oracle绝大部分内存区域是空的,但实践证明,即使在数据启动不久,当业务有违反唯一性约束时,Oracle抛出ora-00001错误,依然迅速。
基于以上两点,我们可以反向推出Oracle肯定有另外的机制查找新更新或者插入的数据是否违反唯一性约束。
带着这些问题,进行如下实验:
1、首先创建测试表格
引用
SQL> create table t11 (id number,name varchar2(100));
Table created.
SQL> insert into t11 select rownum id,dbms_random.string(‘a’,30) name from dual connect by level<=200000;
200000 rows created.
SQL> commit;
Commit complete.
增加唯一索引
引用
SQL> create unique index t11_idx on t11(id);
Index created
测试表格和索引的对象头如下:
引用
SQL> select HEADER_FILE,HEADER_BLOCK from dba_segments where SEGMENT_NAME=‘T11’ and owner=‘ZHOUL’;
HEADER_FILE HEADER_BLOCK
15 41867
SQL> select HEADER_FILE,HEADER_BLOCK from dba_segments where SEGMENT_NAME=‘T11_IDX’ and owner=‘ZHOUL’;
HEADER_FILE HEADER_BLOCK
15 51083
为观察结果,将buffer_cache清空:
引用
SQL> alter system flush buffer_cache;
System altered.
采用10046进行跟踪
引用
SQL> ALTER SESSION SET EVENTS ‘10046 trace name context forever, level 12’;
Session altered.
SQL> insert into t11 values(10,‘test1’);
insert into t11 values(10,‘test1’)
*
ERROR at line 1:
ORA-00001: unique constraint (ZHOUL.T11_IDX) violated
SQL> ALTER SESSION SET EVENTS ‘10046 trace name context off’;
Session altered.
解析跟踪文件可以看到数据库执行的情况
引用
PARSING IN CURSOR #2 len=34 dep=0 uid=60 oct=2 lid=60 tim=1277628749310436 hv=3967311368 ad=‘277a7894’
insert into t11 values(10,‘test1’)
END OF STMT
PARSE #2:c=0,e=472,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=1277628749310431
BINDS #2: