Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2896309
  • 博文数量: 599
  • 博客积分: 16398
  • 博客等级: 上将
  • 技术积分: 6875
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-30 12:04
个人简介

WINDOWS下的程序员出身,偶尔也写一些linux平台下小程序, 后转行数据库行业,专注于ORACLE和DB2的运维和优化。 同时也是ios移动开发者。欢迎志同道合的朋友一起研究技术。 数据库技术交流群:58308065,23618606

文章分类

全部博文(599)

文章存档

2014年(12)

2013年(56)

2012年(199)

2011年(105)

2010年(128)

2009年(99)

分类: Oracle

2012-01-10 12:58:37

如果我们插入的记录违反了约束,那么ORACLE会将约束的名称抛给我们,此种错误会有一定的系统开销,因为在后台ORACLE进行递归SQL调用进行约束名的查询。
 
看如下一个间的例子:
> CREATE TABLE TEST
  2  AS
  3  SELECT * FROM ALL_OBJECTS;
Table created.

> ALTER TABLE TEST ADD PRIMARY KEY(OBJECT_ID);
Table altered.
首先创建了一个带有主键的表。
> set timing on
> alter session set sql_trace=true;
Session altered.
Elapsed: 00:00:00.00
> declare
  2    cursor mycursor is select * from test;
  3    test_rec test%rowtype;
  4  begin
  5     open mycursor;
  6     loop
  7       fetch mycursor into test_rec;
  8       exit when mycursor%notfound;
  9       begin
 10          insert into test values test_rec;
 11       exception
 12          when dup_val_on_index then
 13            null;
 14       end;
 15     end loop;
 16     commit;
 17     close mycursor;
 18  end;
 19  /
PL/SQL procedure successfully completed.
Elapsed: 00:07:56.83
> alter session set sql_trace=false;
Session altered.
Elapsed: 00:00:00.00
> select count(1) from test;
  COUNT(1)
----------
    391820
Elapsed: 00:00:00.06

391820条记录插入的时间大约为8分钟,当然由于主键重复导致这391820条记录全部拒绝掉。
[oracle@dbserver udump]$ tkprof dbtest_ora_390012.trc test.txt
TKPROF: Release 10.2.0.4.0 - Production on Tue Jan 10 12:24:11 2012
Copyright (c) 1982, 2007, Oracle.  All rights reserved.
在后台跟踪文件中可以找到如下的SQL语句:
select /*+ rule */ c.name, u.name
from
 con$ c, cdef$ cd, user$ u  where c.con# = cd.con# and cd.enabled = :1 and
  c.owner# = u.user#

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse   391820      0.16       5.27          0          0          0           0
Execute 391820      0.18       9.57          0          0          0           0
Fetch   391820      0.69      18.18          0    3526380          0      391820
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total   1175460      1.03      33.04          0    3526380          0      391820
Misses in library cache during parse: 0
Optimizer mode: RULE
Parsing user id: SYS   (recursive depth: 2)
Rows     Row Source Operation
-------  ---------------------------------------------------
      1  NESTED LOOPS  (cr=9 pr=0 pw=0 time=131 us)
      1   NESTED LOOPS  (cr=6 pr=0 pw=0 time=96 us)
      1    TABLE ACCESS BY INDEX ROWID CDEF$ (cr=3 pr=0 pw=0 time=51 us)
      1     INDEX RANGE SCAN I_CDEF4 (cr=2 pr=0 pw=0 time=36 us)(object id 53)
      1    TABLE ACCESS BY INDEX ROWID CON$ (cr=3 pr=0 pw=0 time=42 us)
      1     INDEX UNIQUE SCAN I_CON2 (cr=2 pr=0 pw=0 time=28 us)(object id 49)
      1   TABLE ACCESS CLUSTER USER$ (cr=3 pr=0 pw=0 time=32 us)
      1    INDEX UNIQUE SCAN I_USER# (cr=1 pr=0 pw=0 time=8 us)(object id 11)
********************************************************************************
这个SQL就是INSERT INTO TEST出现错误导致的递归SQL语句,主要用来检索引起冲突的唯一约束的主键名(即下面的yansp.SYS_C002103602)。
譬如:
> insert into test select * from test where rownum=1;
insert into test select * from test where rownum=1
*
ERROR at line 1:
ORA-00001: unique constraint (yansp.SYS_C002103602) violated

Elapsed: 00:00:00.01

本例中因为检索违反约束的约束名导致了33.04秒的系统开销。
 
 
如果大部分语句都是违法约束的,因此上面的SQL可以修改为:

SQL> declare
  2    cursor mycursor is select * from test;
  3    test_rec test%rowtype;
  4    v_objid test.object_id%type;
  5  begin
  6     open mycursor;
  7     loop
  8       fetch mycursor into test_rec;
  9       exit when mycursor%notfound;
 10       begin
 11          select object_id into v_objid
 12          from test where object_id=test_rec.object_id;
 13       exception
 14          when no_data_found then
 15            insert into test values test_rec;
 16       end;
 17     end loop;
 18     commit;
 19     close mycursor;
 20  end;
 21  /
PL/SQL procedure successfully completed.
Elapsed: 00:00:19.01
SQL>

因此程序中避免违反约束的产生也是提高性能的一种方法。
 
譬如:
for x in ( set of records )
   loop
        begin
              insert into table
        exception
              when dup_val_on_index then update ...
        end
   end loop;
可以修改为:
   for x in ( set of records )
   loop
       update ...
       if ( sql%rowcount = 0 )
       then
            insert ....
       end if;
   end loop

或者:

   insert into t
   select :pk, :bv1, :bv2, :bv3 from dual
    where not exists (select 1 from T where pk = :pk );
 
   if ( sql%rowcount = 0 )
   then
      duplication record logic here or just raise dup_val_on_index
   end if;
 
 

 
阅读(1685) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~