Oracle关于ORA-08006和ORA-30926一点有趣的测试

 

Oracle关于ORA-08006和ORA-30926一点有趣的测试

 

两个报错的详细信息如下:

ORA-08006: specified row no longer exists

ORA-30926: unable to get a stable set of rows in the source tables/ORA-30926: 无法在源表中获得一组稳定的行

 

现有表zkm,根据如下一样的测试流程,表zkm是否为分区表会影响merge into报错结果为ORA-08006还是ORA-30926,非常的神奇。

复制代码
16:17:25 ZKM@szceb(131)> create table zkm (id int, name varchar2(20))||16:17:54 ZKM@szceb(131)> create table zkm (id int, name varchar2(20));
16:17:29   2      partition by list (name)                           ||                                                                      
16:17:29   3      (partition p1 values('a'),                         ||Table created.                                                        
16:17:29   4       partition p2 values('b')                          ||                                                                      
16:17:29   5      )                                                  ||Elapsed: 00:00:00.02                                                  
16:17:29   6  enable row movement;                                   ||                                                                      
                                                                     ||                                                                      
Table created.                                                       ||                                                                      
                                                                     ||                                                                      
Elapsed: 00:00:00.02                                                 ||                                                                      
16:17:30 ZKM@szceb(131)> insert into zkm values (1, 'a');            ||16:17:58 ZKM@szceb(131)> insert into zkm values (1, 'a');             
                                                                     ||                                                                      
1 row created.                                                       ||1 row created.                                                        
                                                                     ||                                                                      
Elapsed: 00:00:00.01                                                 ||Elapsed: 00:00:00.01                                                  
16:17:32 ZKM@szceb(131)> commit;                                     ||16:18:01 ZKM@szceb(131)> commit;                                      
                                                                     ||                                                                      
Commit complete.                                                     ||Commit complete.                                                      
                                                                     ||                                                                      
Elapsed: 00:00:00.00                                                 ||Elapsed: 00:00:00.00                                                  
16:17:34 ZKM@szceb(131)> merge into zkm                              ||16:18:03 ZKM@szceb(131)> merge into zkm                               
16:17:41   2  using (select 1 id2,'b' new_name from dual             ||16:18:07   2  using (select 1 id2,'b' new_name from dual              
16:17:41   3         connect by level <= 2                           ||16:18:07   3         connect by level <= 2                            
16:17:41   4        ) u                                              ||16:18:07   4        ) u                                               
16:17:41   5  on (zkm.id = u.id2)                                    ||16:18:07   5  on (zkm.id = u.id2)                                     
16:17:41   6  when matched then                                      ||16:18:07   6  when matched then                                       
16:17:41   7    update set name=new_name;                            ||16:18:07   7    update set name=new_name;                             
merge into zkm                                                       ||merge into zkm                                                        
           *                                                         ||           *                                                          
ERROR at line 1:                                                     ||ERROR at line 1:                                                      
ORA-08006: specified row no longer exists                            ||ORA-30926: unable to get a stable set of rows in the source tables    


附:
16:22:09 ZKM@szceb(131)> select 1 id2,'b' new_name from dual
16:31:31   2  connect by level <= 2;

       ID2 NEW
---------- ---
         1 b
         1 b
复制代码

 

从侧面也能看出来ORA-08006实际上就是表zkm匹配了u表第一行后将(1,'a')改为了(1,'b'),由于'b'已经在p2分区,这之后同时表zkm原本同一行匹配了u表第二行,但那一行已经不在p1分区因此报错ORA-08006。

而如果表zkm并非不是分区表,同样的测试方法报错确是ORA-30926: unable to get a stable set of rows in the source tables。

根据上边分析ORA-08006报错原因可以看出来,当实际源表u有多组同时匹配的行的时候,会依次根据u匹配的行先被update,而后才报错,而并非一开始就对拒绝update这个动作。

那么ORA-30926呢?

此时做一次dump表zkm那一行所在的数据块(接着右边非分区表),获取Itl的信息:

复制代码
16:49:41 SYS@testdb(131)> alter system flush buffer_cache;
16:50:23 SYS@testdb(131)> conn zkm/zkm
16:50:24 ZKM@testdb(131)> select dbms_rowid.rowid_relative_fno(rowid) file_id,dbms_rowid.rowid_block_number(rowid) block_id,zkm.* from zkm;

   FILE_ID   BLOCK_ID         ID NAME
---------- ---------- ---------- -------------------------
         4        150          1 a

16:50:28 ZKM@testdb(131)> alter system dump datafile 4 block 150;
16:50:42 ZKM@testdb(131)> col value for a100
16:50:49 ZKM@testdb(131)> select value from v$diag_info where name like 'De%';

VALUE
----------------------------------------------------------------------------------------------------
/u01/app/oracle/diag/rdbms/testdb/testdb/trace/testdb_ora_11922.trc

部分 testdb_ora_11922.trc 内容:
 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0005.00c.000004bb  0x00c00c41.0157.02  --U-    1  fsc 0x0000.0018fbfc
0x02   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
bdba: 0x01000096
data_block_dump,data header at 0x7ffff4e4da64
===============
tsiz: 0x1f98
hsiz: 0x14
pbl: 0x7ffff4e4da64
     76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0x1f90
avsp=0x1f7b
tosp=0x1f7b
0xe:pti[0]      nrow=1  offs=0
0x12:pri[0]     offs=0x1f90
block_row_dump:
tab 0, row 0, @0x1f90
tl: 8 fb: --H-FL-- lb: 0x1  cc: 2    --lb:lock byte,0x1表示此数据行指向上边事务槽Itl为0x01的事务。
col  0: [ 2]  c1 02                  --值 1 的16进制
col  1: [ 1]  61                     --值'a'的16进制
end_of_block_dump

附:
10:22:23 SYS@testdb(101)> select dump(1,1016) col0,dump('a',1016) col1 from dual;

COL0 COL1
------------------- ---------------------------------------
Typ=2 Len=2: c1,2 Typ=96 Len=1 CharacterSet=ZHS16GBK: 61
复制代码

 

接着在原来会话执行merge into,会自动在会话的trc文件产生trace信息。

如下:

对应Itl为0x02的行,其Flag列值为"----",表示当时的事务是活动的,或者在块清除前提交事务。

而col 1(即name列)的值为'b',已经是被修改的状态(当然,报错后自动回滚了)。

复制代码
[root@dbtest ~]# echo '' > /u01/app/oracle/diag/rdbms/testdb/testdb/trace/testdb_ora_11922.trc

09:19:25 ZKM@testdb(131)> merge into zkm
09:19:25   2  using (select 1 id2,'b' new_name from dual
09:19:25   3         connect by level <= 2
09:19:26   4        ) u
09:19:26   5  on (zkm.id = u.id2)
09:19:26   6  when matched then
09:19:26   7    update set name=new_name;
merge into zkm
           *
ERROR at line 1:
ORA-30926: unable to get a stable set of rows in the source tables

截取自动在testdb_ora_11922.trc产生的部分信息:
 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0005.00c.000004bb  0x00c00c41.0157.02  C---    0  scn 0x0000.0018fbfc
0x02   0x0003.017.000004d0  0x00c00960.0121.12  ----    1  fsc 0x0000.00000000
bdba: 0x01000096
data_block_dump,data header at 0xb29b0064
===============
tsiz: 0x1f98
hsiz: 0x14
pbl: 0xb29b0064
     76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0x1f90
avsp=0x1f7b
tosp=0x1f7b
0xe:pti[0]      nrow=1  offs=0
0x12:pri[0]     offs=0x1f90
block_row_dump:
tab 0, row 0, @0x1f90
tl: 8 fb: --H-FL-- lb: 0x2  cc: 2    --0x02的事务。
col  0: [ 2]  c1 02                 --值 1
col  1: [ 1]  62                    --值'b'
end_of_block_dump
复制代码

 

从这可以看出,merge into即便是遇到ORA-30926后,还是会产生事务,同ORA-08006。

只不过该事务转瞬即逝,无法在视图v$transaction中查看对应信息。

不过,这里可以看自动生产的trace信息中的ITL事务,挖挖看当时产生的undo。

提取信息:

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x02   0x0003.017.000004d0  0x00c00960.0121.12  ----    1  fsc 0x0000.00000000

 

Xid:

usn=0003,对应undo段序号为3

slot=017,对应事务表槽号为23(0x017转为10进制:1*16+7=23)

wrap=000004d0,对应被覆盖次数为1232(0x4d0转10进制:4*16*16+13*16=1232)

其中,usn即v$transaction.xidusn

slot即v$transaction.xidslot

wrap即v$transaction.xidsqn

undo序号3的段名为:

10:11:03 SYS@testdb(193)> select name from v$rollname where usn=3;

NAME
-------------------------
_SYSSMU3_2556918060$

 

Uba:

DBA=00c00960,回滚块地址值10进制:12585312

seq#=0121,覆盖次数289

rec#=12,块中第18行

关于DBA(Data Block Address)中包含了undo块的文件号和块地址,以下演示如何分区获取:

复制代码
10:07:22 SYS@testdb(193)> --转10进制 
10:07:27 SYS@testdb(193)> select to_number('00c00960','xxxxxxxx') from dual;

TO_NUMBER('00C00960','XXXXXXXX')
--------------------------------
                        12585312

10:07:31 SYS@testdb(193)> select dbms_utility.data_block_address_file(12585312) file_id from dual;

   FILE_ID
----------
         3

10:07:55 SYS@testdb(193)> select dbms_utility.data_block_address_block(12585312) block_id from dual;

  BLOCK_ID
----------
      2400
复制代码

 

该事务使用的undo块地址在3号文件的2400号块。

dump看看,并找到trc文件中rec#=0x12处的记录,如下:

复制代码
10:12:21 SYS@testdb(193)> col value for a100
10:12:35 SYS@testdb(193)> select value from v$diag_info where name like 'De%';

VALUE
----------------------------------------------------------------------------------------------------
/u01/app/oracle/diag/rdbms/testdb/testdb/trace/testdb_ora_30168.trc

10:19:02 SYS@testdb(193)> alter system flush buffer_cache;
10:19:14 SYS@testdb(193)> alter system dump datafile 3 block 2400;

testdb_ora_30168.trc文件,对应rec#
=0x12的相关记录:
*----------------------------- * Rec #0x12 slt: 0x17 objn: 88290(0x000158e2) objd: 88290 tblspc: 4(0x00000004) * Layer: 11 (Row) opc: 1 rci 0x11 Undo type: Regular undo User Undo Applied Last buffer split: No Temp Object: No Tablespace Undo: No rdba: 0x00000000 *----------------------------- KDO undo record: KTB Redo op: 0x02 ver: 0x01 compat bit: 4 (post-11) padding: 1 op: C uba: 0x00c00960.0121.11 KDO Op code: URP row dependencies Disabled xtype: XA flags: 0x00000000 bdba: 0x01000096 hdba: 0x01000092 itli: 2 ispac: 0 maxfr: 4858 tabn: 0 slot: 0(0x0) flag: 0x2c lock: 2 ckix: 0 ncol: 2 nnew: 1 size: 0 col 1: [ 1] 61 <--这里表示数据的前镜像,即'a'
复制代码

 

看来merge into无论是ORA-08006和ORA-30926,对于多条记录还是会先被update,然后才报错。

但是,又发现另外个现象,对于源表即使有多条记录,也不一定报错,

复制代码
10:49:29 ZKM@testdb(131)> select * from zkm;

        ID NAME
---------- -------------------------
         1 a

Elapsed: 00:00:00.00
10:49:33 ZKM@testdb(131)> merge into zkm
10:49:34   2  using (select 1 id2,'b' new_name from dual
10:49:34   3         connect by level <= 2
10:49:34   4        ) u
10:49:34   5  on (zkm.id = u.id2)
10:49:34   6  when matched then
10:49:34   7    update set name='a';

2 rows merged.
复制代码

嗯。。非常的神奇。。

 

参考链接

https://asktom.oracle.com/ords/f?p=100:11:::::P11_QUESTION_ID:9537705900346441288

https://asktom.oracle.com/ords/f?p=100:11:705597715325014:::::

https://www.modb.pro/db/6953

posted @   PiscesCanon  阅读(88)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示