Chinaunix首页 | 论坛 | 博客
  • 博客访问: 103739074
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类: Oracle

2008-04-24 20:51:50

发表人:dbaoracle

按照Oracle文档中的说法,当使用多表插入(Multi-table-insert)语句时子查询中不能使用sequence:
SQL> create sequence seq ;

序列已创建。

SQL> insert all
2 INTO T1
3 (C1)
4 VALUES
5 (C1)
6 INTO T2
7 (C1)
8 VALUES
9 (C1)
10 select seq.nextval AS C1 from EMP;
select seq.nextval AS C1 from EMP
*
ERROR 位于第 10 行:
ORA-02287: 此处不允许序号

我们可以通过使用一个函数来绕过该限制。


为了绕过这个限制,我们将该sequence放到一个函数中,然后我们调用该函数生成序列号:
SQL> CREATE OR REPLACE FUNCTION f_get_sequence
2 RETURN CHAR
3 AS
4 /***********************************
5 设计说明:
6 1.
7 ************************************/
8 vv_seq VARCHAR2(24);
9 BEGIN
10 select seq.nextval into vv_seq from dual;
11 vv_seq := lpad(vv_seq, 24, '0') ;
12 RETURN vv_seq;
13 EXCEPTION
14 WHEN OTHERS THEN
15 raise;
16 END;
17 /

函数已创建。

SQL> insert all
2 INTO T1
3 (C1)
4 VALUES
5 (C1)
6 INTO T2
7 (C1)
8 VALUES
9 (C1)
10 select f_get_sequence AS C1 from EMP;

已创建28行。

SQL> select * from t1;

C1
------------------------
000000000000000000000002
000000000000000000000004
000000000000000000000006
000000000000000000000008
000000000000000000000010
000000000000000000000012
000000000000000000000014
000000000000000000000016
000000000000000000000018
000000000000000000000020
000000000000000000000022
000000000000000000000024
000000000000000000000026
000000000000000000000028

已选择14行。

SQL> select * from t2;

C1
------------------------
000000000000000000000003
000000000000000000000005
000000000000000000000007
000000000000000000000009
000000000000000000000011
000000000000000000000013
000000000000000000000015
000000000000000000000017
000000000000000000000019
000000000000000000000021
000000000000000000000023
000000000000000000000025
000000000000000000000027
000000000000000000000029

已选择14行。

从结果中可以看到,这样虽然能插入数据,但是两个表中的数据不一样,这也不是我们想要的结果。
有没有什么方法能让插入到两个表中的数据完全一样呢?
在《Effective Oracle by design》这本书中,Tom讲了几种用rownum伪列进行性能调整的方法,
其中提到:如果子查询中有rownum,则该子查询将先被实体化,然后用于语句的其它部分。
我们的这个问题能通过rownum的使用来解决吗?做个测试就明白了:
SQL> rollback;

回退已完成。

SQL> select * from t1;

未选定行

SQL> select * from t2;

未选定行

SQL> insert all
2 INTO T1
3 (C1)
4 VALUES
5 (C1)
6 INTO T2
7 (C1)
8 VALUES
9 (C1)
10 select f_get_sequence AS C1,rownum AS rn from EMP;

已创建28行。

SQL> select * from t1;

C1
------------------------
000000000000000000000030
000000000000000000000031
000000000000000000000032
000000000000000000000033
000000000000000000000034
000000000000000000000035
000000000000000000000036
000000000000000000000037
000000000000000000000038
000000000000000000000039
000000000000000000000040
000000000000000000000041
000000000000000000000042
000000000000000000000043

已选择14行。

SQL> select * from t2;

C1
------------------------
000000000000000000000030
000000000000000000000031
000000000000000000000032
000000000000000000000033
000000000000000000000034
000000000000000000000035
000000000000000000000036
000000000000000000000037
000000000000000000000038
000000000000000000000039
000000000000000000000040
000000000000000000000041
000000000000000000000042
000000000000000000000043

已选择14行。

看到这些,我们应该高兴了,通过这种方法实现了向两个表中插入相同的数据。
对于这两个insert语句,唯一的差别就是第二个语句中多了一个rownum伪列,
为什么会有这么大的不同呢?通过做一个10046跟踪,我们可以看看后台发生了什么:

不带rownum伪列的:
********************************************************************************

insert all
INTO T1
(C1)
VALUES
(C1)
INTO T2
(C1)
VALUES
(C1)
select f_get_sequence AS C1 from EMP

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.07 0.06 0 5 3 28
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.07 0.07 0 5 3 28

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 27

Rows Row Source Operation
------- ---------------------------------------------------
1 MULTI-TABLE INSERT (cr=90 r=0 w=0 time=167006 us)
14 TABLE ACCESS FULL EMP (cr=3 r=0 w=0 time=52 us)
********************************************************************************

SELECT seq.nextval
from
dual


call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.01 0 0 0 0
Execute 28 0.01 0.03 0 0 0 0
Fetch 28 0.00 0.01 0 84 1 28
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 57 0.03 0.05 0 84 1 28

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 27 (recursive depth: 1)

Rows Row Source Operation
------- ---------------------------------------------------
28 SEQUENCE (cr=85 r=0 w=0 time=56735 us)
28 TABLE ACCESS FULL DUAL (cr=84 r=0 w=0 time=681 us)

********************************************************************************

带有rownum伪列的:
********************************************************************************

insert all
INTO T1
(C1)
VALUES
(C1)
INTO T2
(C1)
VALUES
(C1)
select f_get_sequence AS C1,rownum AS rn from EMP

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.01 0.04 0 5 3 28
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.01 0.04 0 5 3 28

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 27

Rows Row Source Operation
------- ---------------------------------------------------
1 MULTI-TABLE INSERT (cr=46 r=0 w=0 time=116157 us)
14 VIEW (cr=46 r=0 w=0 time=116041 us)
14 COUNT (cr=3 r=0 w=0 time=78 us)
14 TABLE ACCESS FULL EMP (cr=3 r=0 w=0 time=57 us)

********************************************************************************

SELECT seq.nextval
from
dual


call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 0 0.00 0.00 0 0 0 0
Execute 14 0.03 0.02 0 0 0 0
Fetch 14 0.03 0.01 0 42 1 14
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 28 0.06 0.03 0 42 1 14

Misses in library cache during parse: 0
Optimizer goal: CHOOSE
Parsing user id: 27 (recursive depth: 1)
********************************************************************************

从跟踪的统计数据来看,带有rownum列的insert语句执行了0.04 秒,不带rownum列的insert语句执行了 0.07 秒,
差别将近一倍;
从执行计划来看,带有rownum列的insert语句将select子句实体化了,而不带rownum列的insert语句则没有;
区别更大的地方还在下面,在带有rownum列的insert语句的执行过程中SELECT seq.nextval from dual这条
递归SQL执行了14次;而不带rownum列的insert语句中,该递归语句执行了28次!整整多出一倍!
这就解释了这两条insert语句的执行时间为什么会有将近一倍的差别。

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