
2008-5-22 16:57
sqysl
一直有个疑问,也一直没做试验,希望和大家一起讨论。。。
问题是:delete from test where 1=2这个语句会在回滚段里分配一个事务槽吗?会在数据段里或数据段里的块上分配信息吗?如果只修改了块的头信息,象:ITL,块的版本号怎末发生变化?存在只修改块头信息而不修改块里数据的情况呢?一起讨论。
2008-5-23 01:54
Yong Huang
No. It does not. Oracle knows you're not getting any rows.
Yong Huang
2008-5-23 07:54
sqysl
thanks for reply,yong huang
2008-5-23 13:39
*迎风*
to Yong Huang
How to oracle know it not getting any rows?
2008-5-23 15:30
晶晶小妹
一个简单的实验即要证明此点:
sid=39 pid=17> delete gk where 0=1;
已删除0行。
sid=43 pid=21> select * from v$transaction;
未选定行
v$transaction视图没有任何行,也就是ORACLE不认为这是一个事务的开始。
我的测试环境是10g
2008-5-23 15:48
Toms_zhang
[quote]原帖由 [i]晶晶小妹[/i] 于 2008-5-23 15:30 发表 [url=http://www.itpub.net/redirect.php?goto=findpost&pid=10457758&ptid=993058][img]http://www.itpub.net/images/common/back.gif[/img][/url]
一个简单的实验即要证明此点:
sid=39 pid=17> delete gk where 0=1;
已删除0行。
sid=43 pid=21> select * from v$transaction;
未选定行
v$transaction视图没有任何行,也就是ORACLE不认为这是一个事务的开始。
我的测试环境是10g [/quote]
are you sure?
2008-5-23 16:00
晶晶小妹
这个实验是我刚做的。
你是不是说:v$transaction中没有行,并不能说明一个事务没有开始。
2008-5-23 18:19
sqysl
以前也和他们讨论过这件事情,我也查了视图资料,V$TRANSACTION,这个视图确实是只显示目前活着的事务,这里没有事务,并不等于一个事务没发生过(V$TRANSACTION lists the active transactions in the system.),你可以查查V$session.TADDR,该字段存储的是事务对象的信息,这个字段在运行了该语句后会产生值的,所以,对这个简单的问题一直比较迷惑,现在谁能把DELETE FROM TEST WHERE 1=2这个语句的内在执行过程清楚的给出就好了,然后可以顺着这个过程做个测试。
[[i] 本帖最后由 sqysl 于 2008-5-23 18:29 编辑 [/i]]
2008-5-24 01:55
Yong Huang
[quote]原帖由 [i]sqysl[/i] 于 2008-5-23 04:19 发表 [url=http://www.itpub.net/redirect.php?goto=findpost&pid=10460113&ptid=993058][img]http://www.itpub.net/images/common/back.gif[/img][/url]
以前也和他们讨论过这件事情,我也查了视图资料,V$TRANSACTION,这个视图确实是只显示目前活着的事务,这里没有事务,并不等于一个事务没发生过 [/quote]
I see what you mean. To find out what locks have been acquired during a very short period of time (too short for you to check in v$lock), you can use event 10704:
conn username/password
select spid from v$process where addr = (select paddr from v$session where sid in (select sid from v$mystat));
alter session set events '10704 trace name context forever, level 10';
--delete from t where rownum = 1;
delete from t where 1 = 2;
alter session set events '10704 trace name context off';
On my 10.2.0.1 database, I see TM lock taken in mode 3. Apparently it means that even if no row is selected, for a brief period, a mode 3 table lock was taken on that table. But since there's no TX lock, we can safely say no transaction took place. If you change the where to actually delete a row, you *will* see TX in the trace file.
Yong Huang
2008-5-24 20:13
sqysl
谢谢yong huang的答复,您说的这些我理解,而且和您有相同的观点,现在关键是有个疑问,[font=黑体][color=Red]那就是ORACLE在开始一个DML语句时,何时获取一个事务槽[/color][/font],无非有以下几种情况:
[color=Red]第一[/color],先不获取事务槽,而是先根据DML对涉及到的数据进行扫描,获取到结果后再获取一个事务槽,然后进行真正的数据操作;关键是这种情况下,如何保证从扫描开始到最后实施真正的修改这段时间里,扫描的数据不被其他事务修改和锁定,TM锁能做到吗?
[color=Red]第二[/color],在开始一个DML时,首先获取一个事务槽,然后对涉及到的数据进行扫描,当对块扫描时,获取一个块ITL,如果这样,无论该块中有没有数据被修改,该事务本身由于获取了ITL,都形成了对该块修改了的事实,即修改了块头;
[color=Red]第三[/color],在开始一个DML时,首先获取一个事务槽,然后对涉及到的数据进行扫描,但在扫描过程中,并不获取ITL,直到扫描某个数据块时,发现该块中有需要加锁修改的数据时,再获取一个块ITL,然后加锁、修改,这种情况下,虽然获取了一个事务槽,但并未修改相应的数据块,不知道这情况算不算获取了一个事务锁。
当然,DELETE FROM TEST WHERE 1=2中的条件ORACLE很容易判断没有符合条件的行,但然过我把WHERE条件换成一个现实的条件,比如:
create table test as select * from dba_extents;
delete from test where owner='####';
而test表里没有符合owner='####'条件的数据时,上面的问题是个什么情况呢?个人愚见,希望大家共同讨论,共同进步。
[[i] 本帖最后由 sqysl 于 2008-5-24 20:19 编辑 [/i]]
2008-5-24 22:12
晶晶小妹
第一点 : ORACLE的确是扫描数据,找到要修改的数据后,再开始修改。从扫描开始到开始实施第一条修改这段时间中,数据不被保护,也没有数据需要保护。
我做如下一个实验。我先以全表扫描更新这个大表中的每一行,马上换到另一个会话,用ROWID更新同一行:
步1:先看看表有多少行:
sid=49 pid=18> select count(*) from test1;
COUNT(*)
----------
727232
步2:在49会话开始更新
sid=49 pid=18> update test1 set object_name=lower(object_name) where object_name='中国';
步3:马上换到43会话,更新ROWID='AAAC83AAEAAAD19AAh'的行,这一行上49会话中要更新的行中的一个:
sid=43 pid=19> update test1 set object_name=upper(object_name) where rowid='AAAC83AAEAAAD19AAh';
已更新 1 行。
步4: 回到49号会话看看,UPDATE被43号会话阻塞。
虽然43号会话中的更新比49号会话的更新晚,但是43号阻塞了49号,因为49号会话描述行的时间比较长。
也就是说,在49号会话找到要更新的数据前,它并不对行加锁。
2008-5-24 22:28
sqysl
首先,谢谢晶晶女侠,学习了,我再确定一下,那你的意思就是:
先进行扫描,扫描到符合修改条件的数据-->获取一个事务表项-->获取一个块ITL-->加锁-->进行数据的修改,是吗?在扫描到符合修改条件的数据前,即不获取事务表项,也不获取块上的ITL,对吗?如果按照这个顺序,那从查到一行符合修改条件的数据,到最后获取事务表项、ITL和行锁,这中间虽然时间非常短暂,这行符合修改条件的数据还是有机会被其他事务修改的,如果这期间被其他会话修改了,也许就不再满足被修改的条件,所以,我觉得肯定有某种机制在扫描前到加锁修改期间保护该行所在数据块不被其他会话扫描修改,是锁?闩?还是被暂时PIN住呢?一起探讨。
[[i] 本帖最后由 sqysl 于 2008-5-24 22:49 编辑 [/i]]
2008-5-24 22:42
晶晶小妹
补充一下,从程序设计的角度上说,ORACLE应该到真正找到要修改的数据了,再分配事务槽。因为如果没有找到满足条件的行,就省去了访问回滚段头的操作。
ORACLE中,能推后的操作,都推后执行。用户发出DML,此时没必要马上去分配事务槽的,都必须分配事务槽时,再去分配。
2008-5-24 22:51
sqysl
首先,谢谢晶晶女侠,学习了,我再确定一下,那你的意思就是:
先进行扫描,扫描到符合修改条件的数据-->获取一个事务表项-->获取一个块ITL-->加锁-->进行数据的修改,是吗?在扫描到符合修改条件的数据前,即不获取事务表项,也不获取块上的ITL,对吗?如果按照这个顺序,那从查到一行符合修改条件的数据,到最后获取事务表项、ITL和行锁,这中间虽然时间非常短暂,这行符合修改条件的数据还是有机会被其他事务修改的,如果这期间被其他会话修改了,也许就不再满足被修改的条件,所以,我觉得肯定有某种机制在扫描前到加锁修改期间保护该行所在数据块不被其他会话扫描修改,是锁?闩?还是被暂时PIN住呢?一起探讨。
2008-5-24 22:54
晶晶小妹
[quote]原帖由 [i]sqysl[/i] 于 2008-5-24 22:28 发表 [url=http://www.itpub.net/redirect.php?goto=findpost&pid=10470899&ptid=993058][img]http://www.itpub.net/images/common/back.gif[/img][/url]
首先,谢谢晶晶女侠,学习了,我再确定一下,那你的意思就是:
先进行扫描,扫描到符合修改条件的数据-->获取一个事务表项-->获取一个块ITL-->加锁-->进行数据的修改,是吗?在扫描到符合修改条件的数据前,即不获取事务表项,也不获取块上的ITL,对吗? [/quote]
是的。这里还有一个实验,可以证明不修改任何行的DML,根本不会访问回滚段头:
sid=36 pid=22> select tch,DBARFIL, DBABLK from x$bh a,(select header_file hf, header_block hb from dba_segments a , v$rollname b where a.segment_name=b.name) b where a.dbarfil=b.hf and a.dbablk=b.hb;
TCH DBARFIL DBABLK
---------- ---------- ----------
61 1 9
43 7 9
42 7 25
41 7 41
这上面显示的是回滚段头的TCH值。DBARFIL 是1的行,是系统回滚段,我们不必看它。主要看下面三行,TCH值分别是43,42,41,注意,相差1。
多观察几次:
sid=36 pid=22> /
TCH DBARFIL DBABLK
---------- ---------- ----------
62 1 9
44 7 9
43 7 25
42 7 41
我观察了很多次,三个回滚段头的TCH值,都是相差1。
下面发出一个更新0行的DML:
sid=43 pid=19> update test1 set object_name='abcdefg' where object_name='9AAh';
已更新0行。
再到36号会话中观察回滚段头的TCH:
sid=36 pid=22> /
TCH DBARFIL DBABLK
---------- ---------- ----------
64 1 9
46 7 9
45 7 25
44 7 41
sid=36 pid=22> /
TCH DBARFIL DBABLK
---------- ---------- ----------
65 1 9
47 7 9
46 7 25
45 7 41
多观察几次,
sid=36 pid=22> /
TCH DBARFIL DBABLK
---------- ---------- ----------
70 1 9
54 7 9
53 7 25
52 7 41
每个回滚段头的TCH始终都是相差1。这证明更新0行的DML并没有访问任何一个回滚段头。
下面,发出一个更新了1行的DML
sid=43 pid=19> update test1 set object_name='abcdefg' where object_name='abcdefg';
已更新 1 行。
sid=36 pid=22> /
TCH DBARFIL DBABLK
---------- ---------- ----------
71 1 9
55 7 9
55 7 25
53 7 41
sid=36 pid=22> /
TCH DBARFIL DBABLK
---------- ---------- ----------
72 1 9
56 7 9
56 7 25
54 7 41
第三行的回滚段头的TCH值发生了变化。
先说这么多吧。这个实验证明,UPDATE 零行的话,是不访问回滚段头的。
2008-5-24 23:11
sqysl
谢谢女侠,学习了
2008-5-28 06:04
Yong Huang
[quote]原帖由 [i]sqysl[/i] 于 2008-5-24 08:51 发表 [url=http://www.itpub.net/redirect.php?goto=findpost&pid=10471161&ptid=993058][img]http://www.itpub.net/images/common/back.gif[/img][/url]
...从查到一行符合修改条件的数据,到最后获取事务表项、ITL和行锁,这中间虽然时间非常短暂,这行符合修改条件的数据还是有机会被其他事务修改的,如果这期间被其他会话修改了,也许就不再满足被修改的条件,所以,我觉得肯定有某种机制在扫描前到加锁修改期间保护该行所在数据块不被其他会话扫描修改,是锁?闩?还是被暂时PIN住呢?一起探讨。 [/quote]
That's no different from a regular select, which is guaranteed to be a consistent read. If another session modifies some data and then this query reads it later, this query will go to undo to read the before image. Whether DML follows doesn't make any difference in the behavior.
Yong Huang
2008-5-28 21:52
sqysl
谢谢yong huang的回复,但我觉得你可能没理解我的意思,我的意思是在执行dml时,系统会扫描表,直到发现一条符合条件的数据行时,系统会获取一个事务槽,ITL,行锁。。。,那么在系统发现该数据行后,与获取事务槽之间,时间再短,也有个时间间隙的,我说的更改是在这个时间段内,被其他会话更改已经被该会话搜索到的数据行,我想在这个短的时间间隙内,应该有机制保护该会话找到的符合修改条件的数据行。如果在这个间隙该数据行被其他会话修改了,应该产生阻塞,而不是去回滚段里找前影像,我记得在修改块数据时数据块被PIN住,但不知道PIN的具体的时机,一起讨论。
2008-5-28 22:01
晶晶小妹
在扫描块时,块上会加共享PIN,如果发现了满足条件行,释放共享PIN,重新获得Cache Bubffer Chain闩,在Buffer cache中定位块,在块中加独占PIN,然后修改ITL槽,加行锁。如果加独占PIN时发现块已经有了共享PIN或独占PIN,就等待。
应该就是这样吧。
2008-5-28 23:08
sqysl
这倒是比较符合逻辑,但这方面介绍这么细微的资料我至今也没找到,暂且这么认为吧,学习。
页:
[1]
2

Powered by ITPUB论坛