没有必胜的秘籍,没有方程式遵循~~
要赢~~只有全身心的投入!
晶晶实验二十二之 直接路径插入篇
上一篇 / 下一篇 2008-04-02 23:24:28 / 个人分类:晶晶oracle实验系列
查看( 625 ) /
评论( 16 )
一、直接路径插入与间接路径插入的不同
UU3G?M3H0 这个问题相信很多人都已经知道了,为了方便初学者,我再来重审一遍。
NM7L9ZC5a#I{Xq0 create table 表1 as select 列1,列2,... select 表2
8h E4ZVG*^,@!C5aS3q0 insert /*+append*/ into 表1 select 列1,列2,... select 表2
&x6e\yb,{D8kO0 如上形式的插入,都叫做直接路径插入。当然,在SQL*Loader中也有直接路径插入的形式。ITPUB个人空间;^]cpG9[h!H
所谓直接路径插入,就是绕过Buffer cache,直接将数据插入进表所在数据文件中。ITPUB个人空间G4vG.|%WD n`
假如有表AA,要将AA中的数据插入进表BB,在普通的间接插入下,先将AA的数据块传进Buffer cache,再将BB的块也传进Buffer cache,在Buffer cache中从AA的块中读出行,插入进BB的块中。BB的块就都变成了脏块,再等待DBWn把它们写进数据文件。因此,间接路径插入后,AA表的块和BB表的块都会在Buffer cache中出现。ITPUB个人空间;sjfRRQqN
而直接路径插入下,将AA表的数据块传进Buffer cache中,读出行,直接写进BB表所在的数据文件。插入完毕后,除了表头块外,BB表的数据块并不会出现在Buffer cache中。
q"`.|FG v_Mq0 下面来试验一下:ITPUB个人空间7rF#z(Y"F\2mv
步1:准备试验用表:
B-w AM~4X7uX-`0 SQL> create table aa(id number(4),name varchar2(5));
iq!e'COl&yjF%j {0 表已创建。
d}6?W#Yn6P8tO)W0 SQL> create table bb(id number(4),name varchar2(5));ITPUB个人空间n6XPAF7p+p
表已创建。
J$\1XsJ+h:b0 SQL> insert into aa values(1,'aa');
(WE|*ZC0 已创建 1 行。
2]x%KR6~"glrd0 SQL> insert into aa values(2,'bb');ITPUB个人空间.`#M$H.qT6M3B
已创建 1 行。ITPUB个人空间;qz| i+Mk2N B
SQL> insert into aa values(3,'cc');ITPUB个人空间2_Xblw`TN$a
已创建 1 行。
ulf^A0 SQL> insert into aa values(4,'dd');ITPUB个人空间*Z6KX0|7CF2[*\IL$e7h
已创建 1 行。
e!te+Fb9H#J4m-{y-u0 SQL> commit;ITPUB个人空间0hr{-BFMBc-L
提交完成。ITPUB个人空间;[ W*~ c0G%FZ{
SQL> select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid) from aa;
L$p9iCh2b0 DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
d _!X0~8i.Bs2s0 ------------------------------------ ------------------------------------ITPUB个人空间jR%a9Mn7N
4 18493
^3xV8vF$pYUvMF0 4 18493ITPUB个人空间YnR"s'Tv s
4 18493
Hq#NJ$z9q"fT&E0 4 18493
KA$A+]7^uFLvF0 现在AA表中有4行,占用块18493。BB表中没有数据。ITPUB个人空间8|CnO g,b)wS"D
步2:将buffer cache清空,我这里使用重启数据库的方法:ITPUB个人空间2Z\4u@z9o%^
SQL> shutdown immediateITPUB个人空间 j#R(aaI SH2S?
SQL> startup
w:m:EYv~0 步3:先用直接路径插入,从AA表向BB表插入数据:ITPUB个人空间(H|H8_ nYK+s7N
SQL> insert /*+ append*/ into bb select * from aa;
;l#OX"}5P0 已创建4行。ITPUB个人空间+JW3e T&I1HZNI
SQL> commit;
0lvM#@[(NP,x0 提交完成。ITPUB个人空间uzfR ox|@6u`-q
步4:使用V$bh查看Buffer cache中的块:
)VP8wxZ7`B `(w0 SQL> select file#,block# from v$bh where objd=(select object_id from user_objects where object_name='AA');
b$x8r_~#UanU8R rv0 FILE# BLOCK#
/c^$mv!X'cU0 ---------- ----------ITPUB个人空间zSS!Z2mo*Z
4 18491ITPUB个人空间.W TYkS+t,t:H
4 18491ITPUB个人空间MMm^ R
4 18494ITPUB个人空间$p sL(r(_?$\yt
4 18492
"L)jO\d)SifQ0 4 18495
CS1~e_\m.H|lG0 4 18493 <---- 当前包含数据的块ITPUB个人空间i$GX` \lU j'Vj
4 18496
{0?Q5w-r rT-K0 已选择7行。
G{Fo"]l}QX0 由于对AA表进行了全表扫描,因此,AA表中高水点下的所有块都被读进了Buffer cache,这其中当然包括包含数据的块18493。ITPUB个人空间"AoWb*\}$S
SQL> select file#,block# from v$bh where objd=(select object_id from user_objects where object_name='BB');ITPUB个人空间 Wvg*]!\1}0s)U
FILE# BLOCK#ITPUB个人空间0q:HDsz h#{(mS
---------- ----------ITPUB个人空间IJV&axC
4 18499
.~-f8JRi RT0 4 18499
bf`&Ozy0 4 18497
c7fH$]Ha,Gq7m?3y8B0 SQL> select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid) from bb;ITPUB个人空间,[ Xk+dE9C _
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)ITPUB个人空间|;T#S#D.k$_
------------------------------------ ------------------------------------
DCo2zZn+p$[0 4 18500ITPUB个人空间C'ZHrPSWUd"@!E
4 18500
7iB9?#us0 4 18500
~Qk)os0 4 18500ITPUB个人空间fO[5T|{L
上面两个查询可以看到,BB表中的数据占用第18500块,但是,直接路径插入后,18500块并没被调进Buffer cache。Buffer cache中只有18499和18497。 其中18499是段头块,而18497是L1块,直接路径插入后,要修改L1块中的数据块使用情况。ITPUB个人空间]-F5b!o9u
步5:再试一次间接路径插入:ITPUB个人空间lX8| D+\2M8W
SQL> insert into bb select * from aa;ITPUB个人空间5GX/czn6\
已创建4行。ITPUB个人空间-KCi'eVL
SQL> commit;
M%`)t$p2TEu2?0 提交完成。
l6Gs NWKY0 SQL> select file#,block# from v$bh where objd=(select object_id from user_objects where object_name='BB');
@u!]`?n5t0 FILE# BLOCK#
f+e)d4s j+S_+D0 ---------- ----------
6QUS/j|M3q X0 4 18504 <---- 本次间接路径插入的数据所在块ITPUB个人空间&NI^V k$`/b
4 18499ITPUB个人空间 E!Uv(R[ |.C'@3m
4 18499
o$s GC G3BNU0 4 18502ITPUB个人空间` s)G9?^ uDc
4 18497
yt5Zr#zx f0 4 18500ITPUB个人空间E0P,BKi
4 18503ITPUB个人空间C(I;P'AG"d9?m
4 18498ITPUB个人空间A9_t\(|
4 18501ITPUB个人空间 Q+g"k@+yT4^$p7A;I(~
已选择9行。
.[j/RB.JZ Z O0 SQL> select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid) from bb;ITPUB个人空间VEM9BYEp+I%F,P
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
2i&t&c0Ue k0 ------------------------------------ ------------------------------------ITPUB个人空间l N/d:z)r5W%G$_:S
4 18500ITPUB个人空间$h2K'q @P bGr
4 18500
&We'u[C0 4 18500ITPUB个人空间Ai4~$VZ*T.P5I
4 18500
%s)lTj lP @Yz0 4 18504
6B`7P7tK([9M0 4 18504ITPUB个人空间F?knH.g| _
4 18504ITPUB个人空间AEE(i{?
4 18504
R'?%K B#d |\W p0 已选择8行。ITPUB个人空间^4p5{2S6~(p'O6M
从上面的实验可以证明,间接路径插入,要先将数据块传进Buffer cache。这是Oracle通常修改数据的方式,不对数据文件直接进行修改,而是在内存中完成修改,再由日志提供保护。对于小量数据的修改,这种方法的性能还是很不错的。但是大量数据的修改,直接路径插入将可以提供更好的性能。ITPUB个人空间?#guf s@D"],C$na
直接路径插入除去少了将BB表的块传进Buffer cache这一步外,它还不产生回滚信息,下面来进一步的实验:ITPUB个人空间3uK!Lp,xn6Y s1^A
二、直接路径插入与回滚:ITPUB个人空间$bO9m#PI0S-u-Hr
步1:再次向BB中直接路径插入:
(l ?QBO0 SQL> insert /*+ append*/ into bb select id+4,name from aa;ITPUB个人空间k'H+W1` a/p!LpoPx
步2:查看事务信息:ITPUB个人空间2n Sr%F%dU)e!N4f
SQL> select xidusn,xidslot,xidsqn,ubafil,ubablk,ubasqn from v$transaction;
!e)g%d-tv-Q1CG1b0 XIDUSN XIDSLOT XIDSQN UBAFIL UBABLK UBASQN
\ sblG4J-J0 ---------- ---------- ---------- ---------- ---------- ----------
hdft0m m0 11 23 854 0 0 0
j!v|J*_Y t%Z0 因为当前只有一个事务,因此选择 v$transaction 视图时没有加条件。从上面的显示结果可以看到,UBAFIL、UBABLK为0。也就是此事务并没有对应的回滚块,只在回滚段头的事务表中占用了一行而已。ITPUB个人空间-};~*e gk9l
直接路径插入是如何提供回滚的呢?观察BB表高水点的变化,就可以解答这个问题:ITPUB个人空间8lzLm^N*vma%D
步3: 查找BB表的高水点:
\Va*D6L;{ q0 SQL> select header_file,header_block from dba_segments where segment_name='BB';
G5P&N zn Ie3h y W0 HEADER_FILE HEADER_BLOCK
!hkP3?0v.q0 ----------- ------------
_/E QR'[0 4 18499
Q.z I1wr,T"s0 SQL> alter system dump datafile 4 block 18499;
(M9u1t mw;K%i0 系统已更改。
UU3G?M3H0 这个问题相信很多人都已经知道了,为了方便初学者,我再来重审一遍。
NM7L9ZC5a#I{Xq0 create table 表1 as select 列1,列2,... select 表2
8h E4ZVG*^,@!C5aS3q0 insert /*+append*/ into 表1 select 列1,列2,... select 表2
&x6e\yb,{D8kO0 如上形式的插入,都叫做直接路径插入。当然,在SQL*Loader中也有直接路径插入的形式。ITPUB个人空间;^]cpG9[h!H
所谓直接路径插入,就是绕过Buffer cache,直接将数据插入进表所在数据文件中。ITPUB个人空间G4vG.|%WD n`
假如有表AA,要将AA中的数据插入进表BB,在普通的间接插入下,先将AA的数据块传进Buffer cache,再将BB的块也传进Buffer cache,在Buffer cache中从AA的块中读出行,插入进BB的块中。BB的块就都变成了脏块,再等待DBWn把它们写进数据文件。因此,间接路径插入后,AA表的块和BB表的块都会在Buffer cache中出现。ITPUB个人空间;sjfRRQqN
而直接路径插入下,将AA表的数据块传进Buffer cache中,读出行,直接写进BB表所在的数据文件。插入完毕后,除了表头块外,BB表的数据块并不会出现在Buffer cache中。
q"`.|FG v_Mq0 下面来试验一下:ITPUB个人空间7rF#z(Y"F\2mv
步1:准备试验用表:
B-w AM~4X7uX-`0 SQL> create table aa(id number(4),name varchar2(5));
iq!e'COl&yjF%j {0 表已创建。
d}6?W#Yn6P8tO)W0 SQL> create table bb(id number(4),name varchar2(5));ITPUB个人空间n6XPAF7p+p
表已创建。
J$\1XsJ+h:b0 SQL> insert into aa values(1,'aa');
(WE|*ZC0 已创建 1 行。
2]x%KR6~"glrd0 SQL> insert into aa values(2,'bb');ITPUB个人空间.`#M$H.qT6M3B
已创建 1 行。ITPUB个人空间;qz| i+Mk2N B
SQL> insert into aa values(3,'cc');ITPUB个人空间2_Xblw`TN$a
已创建 1 行。
ulf^A0 SQL> insert into aa values(4,'dd');ITPUB个人空间*Z6KX0|7CF2[*\IL$e7h
已创建 1 行。
e!te+Fb9H#J4m-{y-u0 SQL> commit;ITPUB个人空间0hr{-BFMBc-L
提交完成。ITPUB个人空间;[ W*~ c0G%FZ{
SQL> select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid) from aa;
L$p9iCh2b0 DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
d _!X0~8i.Bs2s0 ------------------------------------ ------------------------------------ITPUB个人空间jR%a9Mn7N
4 18493
^3xV8vF$pYUvMF0 4 18493ITPUB个人空间YnR"s'Tv s
4 18493
Hq#NJ$z9q"fT&E0 4 18493
KA$A+]7^uFLvF0 现在AA表中有4行,占用块18493。BB表中没有数据。ITPUB个人空间8|CnO g,b)wS"D
步2:将buffer cache清空,我这里使用重启数据库的方法:ITPUB个人空间2Z\4u@z9o%^
SQL> shutdown immediateITPUB个人空间 j#R(aaI SH2S?
SQL> startup
w:m:EYv~0 步3:先用直接路径插入,从AA表向BB表插入数据:ITPUB个人空间(H|H8_ nYK+s7N
SQL> insert /*+ append*/ into bb select * from aa;
;l#OX"}5P0 已创建4行。ITPUB个人空间+JW3e T&I1HZNI
SQL> commit;
0lvM#@[(NP,x0 提交完成。ITPUB个人空间uzfR ox|@6u`-q
步4:使用V$bh查看Buffer cache中的块:
)VP8wxZ7`B `(w0 SQL> select file#,block# from v$bh where objd=(select object_id from user_objects where object_name='AA');
b$x8r_~#UanU8R rv0 FILE# BLOCK#
/c^$mv!X'cU0 ---------- ----------ITPUB个人空间zSS!Z2mo*Z
4 18491ITPUB个人空间.W TYkS+t,t:H
4 18491ITPUB个人空间MMm^ R
4 18494ITPUB个人空间$p sL(r(_?$\yt
4 18492
"L)jO\d)SifQ0 4 18495
CS1~e_\m.H|lG0 4 18493 <---- 当前包含数据的块ITPUB个人空间i$GX` \lU j'Vj
4 18496
{0?Q5w-r rT-K0 已选择7行。
G{Fo"]l}QX0 由于对AA表进行了全表扫描,因此,AA表中高水点下的所有块都被读进了Buffer cache,这其中当然包括包含数据的块18493。ITPUB个人空间"AoWb*\}$S
SQL> select file#,block# from v$bh where objd=(select object_id from user_objects where object_name='BB');ITPUB个人空间 Wvg*]!\1}0s)U
FILE# BLOCK#ITPUB个人空间0q:HDsz h#{(mS
---------- ----------ITPUB个人空间IJV&axC
4 18499
.~-f8JRi RT0 4 18499
bf`&Ozy0 4 18497
c7fH$]Ha,Gq7m?3y8B0 SQL> select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid) from bb;ITPUB个人空间,[ Xk+dE9C _
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)ITPUB个人空间|;T#S#D.k$_
------------------------------------ ------------------------------------
DCo2zZn+p$[0 4 18500ITPUB个人空间C'ZHrPSWUd"@!E
4 18500
7iB9?#us0 4 18500
~Qk)os0 4 18500ITPUB个人空间fO[5T|{L
上面两个查询可以看到,BB表中的数据占用第18500块,但是,直接路径插入后,18500块并没被调进Buffer cache。Buffer cache中只有18499和18497。 其中18499是段头块,而18497是L1块,直接路径插入后,要修改L1块中的数据块使用情况。ITPUB个人空间]-F5b!o9u
步5:再试一次间接路径插入:ITPUB个人空间lX8| D+\2M8W
SQL> insert into bb select * from aa;ITPUB个人空间5GX/czn6\
已创建4行。ITPUB个人空间-KCi'eVL
SQL> commit;
M%`)t$p2TEu2?0 提交完成。
l6Gs NWKY0 SQL> select file#,block# from v$bh where objd=(select object_id from user_objects where object_name='BB');
@u!]`?n5t0 FILE# BLOCK#
f+e)d4s j+S_+D0 ---------- ----------
6QUS/j|M3q X0 4 18504 <---- 本次间接路径插入的数据所在块ITPUB个人空间&NI^V k$`/b
4 18499ITPUB个人空间 E!Uv(R[ |.C'@3m
4 18499
o$s GC G3BNU0 4 18502ITPUB个人空间` s)G9?^ uDc
4 18497
yt5Zr#zx f0 4 18500ITPUB个人空间E0P,BKi
4 18503ITPUB个人空间C(I;P'AG"d9?m
4 18498ITPUB个人空间A9_t\(|
4 18501ITPUB个人空间 Q+g"k@+yT4^$p7A;I(~
已选择9行。
.[j/RB.JZ Z O0 SQL> select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid) from bb;ITPUB个人空间VEM9BYEp+I%F,P
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
2i&t&c0Ue k0 ------------------------------------ ------------------------------------ITPUB个人空间l N/d:z)r5W%G$_:S
4 18500ITPUB个人空间$h2K'q @P bGr
4 18500
&We'u[C0 4 18500ITPUB个人空间Ai4~$VZ*T.P5I
4 18500
%s)lTj lP @Yz0 4 18504
6B`7P7tK([9M0 4 18504ITPUB个人空间F?knH.g| _
4 18504ITPUB个人空间AEE(i{?
4 18504
R'?%K B#d |\W p0 已选择8行。ITPUB个人空间^4p5{2S6~(p'O6M
从上面的实验可以证明,间接路径插入,要先将数据块传进Buffer cache。这是Oracle通常修改数据的方式,不对数据文件直接进行修改,而是在内存中完成修改,再由日志提供保护。对于小量数据的修改,这种方法的性能还是很不错的。但是大量数据的修改,直接路径插入将可以提供更好的性能。ITPUB个人空间?#guf s@D"],C$na
直接路径插入除去少了将BB表的块传进Buffer cache这一步外,它还不产生回滚信息,下面来进一步的实验:ITPUB个人空间3uK!Lp,xn6Y s1^A
二、直接路径插入与回滚:ITPUB个人空间$bO9m#PI0S-u-Hr
步1:再次向BB中直接路径插入:
(l ?QBO0 SQL> insert /*+ append*/ into bb select id+4,name from aa;ITPUB个人空间k'H+W1` a/p!LpoPx
步2:查看事务信息:ITPUB个人空间2n Sr%F%dU)e!N4f
SQL> select xidusn,xidslot,xidsqn,ubafil,ubablk,ubasqn from v$transaction;
!e)g%d-tv-Q1CG1b0 XIDUSN XIDSLOT XIDSQN UBAFIL UBABLK UBASQN
\ sblG4J-J0 ---------- ---------- ---------- ---------- ---------- ----------
hdft0m m0 11 23 854 0 0 0
j!v|J*_Y t%Z0 因为当前只有一个事务,因此选择 v$transaction 视图时没有加条件。从上面的显示结果可以看到,UBAFIL、UBABLK为0。也就是此事务并没有对应的回滚块,只在回滚段头的事务表中占用了一行而已。ITPUB个人空间-};~*e gk9l
直接路径插入是如何提供回滚的呢?观察BB表高水点的变化,就可以解答这个问题:ITPUB个人空间8lzLm^N*vma%D
步3: 查找BB表的高水点:
\Va*D6L;{ q0 SQL> select header_file,header_block from dba_segments where segment_name='BB';
G5P&N zn Ie3h y W0 HEADER_FILE HEADER_BLOCK
!hkP3?0v.q0 ----------- ------------
_/E QR'[0 4 18499
Q.z I1wr,T"s0 SQL> alter system dump datafile 4 block 18499;
(M9u1t mw;K%i0 系统已更改。