现象:
在表上面新建主键报
ORA-08102的异常:
SQL> alter table t add primary key(id);
alter table t add primary key(id)
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-08102: index key not found, obj# 52, file 1, block 72661 (2)
重现异常:
1、查看基表CON$的_NEXT_CONSTRAINT信息和数据块:
SQL> SELECT OWNER#,NAME,CON# FROM CON$ WHERE NAME='_NEXT_CONSTRAINT';
OWNER# NAME CON#
---------- ------------------------------ ----------
0 _NEXT_CONSTRAINT 11222
SQL> set lines 200
SELECT OWNER#,NAME,CON#,
dbms_rowid.ROWID_RELATIVE_FNO(rowid) fno,
dbms_rowid.ROWID_BLOCK_NUMBER(rowid) bno,
dbms_rowid.ROWID_ROW_NUMBER(rowid) rno FROM CON$ WHERE NAME='_NEXT_CONSTRAINT';
OWNER# NAME CON# FNO BNO RNO
---------- ------------------------------ ---------- ---------- ---------- ----------
0 _NEXT_CONSTRAINT 11222 1 289 12
记录存储在1号文件、289号block、第12行。
2、使用BBED查看数据块
选择1号文件第289号block:
[oracle@cqfrog bbed]$ bbed parfile=par.txt
BBED> set file 1 block 289
FILE# 1
BLOCK# 289
打印第12行:
- BBED> p *kdbr[12]
rowdata[0]
----------
ub1 rowdata[0] @1207 0x2c
格式化显示:
- BBED> x /rccnn
rowdata[0] @1207
----------
flag@1207: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@1208: 0x02
cols@1209: 4
col 0[1] @1210: .
col 1[16] @1212: _NEXT_CONSTRAINT
col 2[4] @1229: 11222
col 3[1] @1234: 0
将offset为1229的信息dump:
BBED> dump /v offset 1229 count 16
File: /u01/app/oracle/oradata/orcl/system01.dbf (1)
Block: 289 Offsets: 1229 to 1244 Dba:0x00400121
-------------------------------------------------------
04c3020d 1701802c 00040180 105f4e45 l .......,....._NE
<16 bytes per line>
查看11222的16进制:
SQL> select dump(11222, 16) from dual;
DUMP(11222,16)
----------------------
Typ=2 Len=4: c3,2,d,17
这里的c3,2,d,17对应dump出来的信息:
c3020d
17。
3、关闭数据库
必须先关闭数据库, 否则修改不生效。
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> exit
Disconnected from Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
4、修改数据块的值
使用bbed
修改数据块的值
, 将11222 改大。
移动4位, 或者使用dump /v offset 1233count 16
:
BBED> dump /v offset +4
File: /u01/app/oracle/oradata/orcl/system01.dbf (1)
Block: 289 Offsets: 1233 to 1248 Dba:0x00400121
-------------------------------------------------------
1701802c 00040180 105f4e45 58545f43 l ...,....._NEXT_C
<16 bytes per line>
将17修改为19:
BBED> modify /x 1901802c
File: /u01/app/oracle/oradata/orcl/system01.dbf (1)
Block: 289 Offsets: 1233 to 1248 Dba:0x00400121
------------------------------------------------------------------------
1901802c 00040180 105f4e45 58545f43
<32 bytes per line>
BBED> sum apply
Check value for File 1, Block 289:
current = 0x7fca, required = 0x7fca
BBED> dump /v offset 1233
File: /u01/app/oracle/oradata/orcl/system01.dbf (1)
Block: 289 Offsets: 1233 to 1248 Dba:0x00400121
-------------------------------------------------------
1901802c 00040180 105f4e45 58545f43 l ...,....._NEXT_C
<16 bytes per line>
5、启动数据库
SQL> startup
ORACLE instance started.
Total System Global Area 835104768 bytes
Fixed Size 2217952 bytes
Variable Size 549455904 bytes
Database Buffers 276824064 bytes
Redo Buffers 6606848 bytes
Database mounted.
Database opened.
6、查看con$表的信息
使用全表扫描方式:
SQL> select /*+ FULL(t1) */ name,con# from con$ t1 where name='_NEXT_CONSTRAINT';
NAME CON#
------------------------------ ----------
_NEXT_CONSTRAINT 11224
使用索引方式:
SQL> select /*+ index(t1 I_CON2) */ name,con# from con$ t1 where name='_NEXT_CONSTRAINT';
NAME CON#
------------------------------ ----------
_NEXT_CONSTRAINT 11222
使用全表扫描和使用索引方式的值相差2。
7、新建测试表并增加主键
SQL> create table t as select * from test where rownum<10;
Table created.
SQL> desc t;
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NUMBER
NAME VARCHAR2(128
SQL> alter table t add primary key(id);
alter table t add primary key(id)
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-08102: index key not found, obj# 52, file 1, block 72661 (2)
观察发现, 有ORA-8102异常。
修复ORA-08102异常:
1、根据报错信息定位数据块
SQL> alter table t add primary key(id);
alter table t add primary key(id)
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-08102: index key not found, obj# 52, file 1, block 72661 (2)
位置:file 1, block 72661
2、查看索引和全表扫描的信息
SQL> select /*+ FULL(t1) */ name,con# from con$ t1 where name='_NEXT_CONSTRAINT';
NAME CON#
------------------------------ ----------
_NEXT_CONSTRAINT 11224
SQL> select /*+ index(t1 I_CON2) */ name,con# from con$ t1 where name='_NEXT_CONSTRAINT';
NAME CON#
------------------------------ ----------
_NEXT_CONSTRAINT 11222
3、dump报错的数据块
根据alert日志或者dump数据块:
SQL> alter system dump datafile 1 block 72661;
System altered.
SQL> select * from v$diag_info;
1 Default Trace File /u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_6051.trc
在dump文件搜索8102错误:
![1110497-20170312015652326-1838651353.png](https://i-blog.csdnimg.cn/blog_migrate/397f443ea4e7e9370e8f3c4b576561ea.png)
可以看到数据块期望的值是:c3 02 0d 19 。11224。
SQL> select UTL_RAW.CAST_TO_NUMBER(replace('c3 02 0d 19',' ','')) from dual;
UTL_RAW.CAST_TO_NUMBER(REPLACE('C3020D19','',''))
-------------------------------------------------
11224
查看dump的文件:
row#198[3566] flag: ---D--, lock: 2, len=13, data:(6): 00 41 38 6c 00 ad
col 0; len 4; (4): c3 02 0d 15
row#199[3540] flag: ---D--, lock: 2, len=13, data:(6): 00 41 38 6c 00 af
col 0; len 4; (4): c3 02 0d 16
row#200[3553] flag: ------, lock: 0, len=13, data:(6): 00 40 01 21 00 0c
col 0; len 4; (4): c3 02 0d 17
----- end of leaf block dump -----
End dump data blocks tsn: 0 file#: 1 minblk 72661 maxblk 72661
找到最后, 图上的红色部分:
00 40 01 21 00 0c 是rowid信息:
文件号:
00 40 (取前十位,1)
块号:
01 21
(289)
行号:
00 0c (12)
注意:这里dump的索引的块, 可以看到对应的数据块的rowid。
我们使用bbed可以看到文件1、数据块289、12行的数据是多少, 这里省略了。
我们看到索引存储的值为:
c3 02 0d 17。
转换为10进制为11222。
SQL> select UTL_RAW.CAST_TO_NUMBER(replace('c3 02 0d 17',' ','')) from dual;
UTL_RAW.CAST_TO_NUMBER(REPLACE('C3020D17','',''))
-------------------------------------------------
11222
从前面的全表扫描的结果, 期望值应该为11224, 因此只需要将索引块值修改为
c3
02
0d
19。 即可与数据块保持一致。
4、使用BBED修复
查找offset的值:
![1110497-20170312015652654-630006238.png](https://i-blog.csdnimg.cn/blog_migrate/b35c18056e3d0509782f0c3c63f3f9c1.png)
查看dump的信息, 索引块的ITL槽位有3个, 可以计算offset如下:
offset =
3553+44+8+24*ITL_CNT
= 3553+44+8+24*3= 3677
指定文件和块:
BBED> set file 1 block 72661;
FILE# 1
BLOCK# 72661
定位到行:
BBED> dump offset 3677 count 16
File: /u01/app/oracle/oradata/orcl/system01.dbf (1)
Block: 72661 Offsets: 3677 to 3692 Dba:0x00411bd5
------------------------------------------------------------------------
04c3020d 17010200 41386c00 ad04c302
修改:
BBED> modify /x 19 offset 3681
File: /u01/app/oracle/oradata/orcl/system01.dbf (1)
Block: 72661 Offsets: 3681 to 3696 Dba:0x00411bd5
------------------------------------------------------------------------
19010200 41386c00 ad04c302 0d150100
<32 bytes per line>
BBED> sum apply
Check value for File 1, Block 72661:
current = 0x1fa3, required = 0x1fa3
BBED> dump offset 3677 count 16
File: /u01/app/oracle/oradata/orcl/system01.dbf (1)
Block: 72661 Offsets: 3677 to 3692 Dba:0x00411bd5
------------------------------------------------------------------------
04c3020d 19010200 41386c00 ad04c302
<32 bytes per line>
5、打开数据库验证
查看全表扫描和索引扫描的值是否一致:
SQL> select /*+ FULL(t1) */ name,con# from con$ t1 where name='_NEXT_CONSTRAINT';
NAME CON#
------------------------------ ----------
_NEXT_CONSTRAINT 11224
SQL> select /*+ index(t1 I_CON2) */ name,con# from con$ t1 where name='_NEXT_CONSTRAINT';
NAME CON#
------------------------------ ----------
_NEXT_CONSTRAINT 11224
验证增加主键能成功:
SQL> alter table t add primary key(id);
Table altered.