ITPub博客

首页 > 数据库 > Oracle > Oracle 索引组织表 ORA-00600 [6200] 处理实战:从十六进制对象号定位到 IOT 重建

Oracle 索引组织表 ORA-00600 [6200] 处理实战:从十六进制对象号定位到 IOT 重建

原创 Oracle 作者:marui 时间:2026-08-10 20:10:49 0 删除 编辑

Oracle 索引组织表 ORA-00600 [6200] 处理实战:从十六进制对象号定位到 IOT 重建

大家好,我是睿。

最近处理了一次比较典型、但又容易让人紧张的 Oracle 故障:数据库 open 后,后台进程不断在 alert 日志和 trace 中报 ORA-00600 [6200] ,同时伴随 ORA-07445 [kghstack_err()+117] 。

ORA-00600 这种错误,很多 DBA 第一眼看到都会头皮一紧。因为它不是普通 SQL 报错,而是 Oracle 内部错误。它可能是 bug,也可能是数据块、索引块、字典对象或者内存访问触发的问题。

这次的关键线索不在 alert 日志表面,而是在 trace 文件里:

**** key (begin=0x14b4, len=983) overlaps with another

begin = 0x14de len = 555

 

---- end index block validation

 

Block header dump:  0x00801e55

Object id on Block? Y

seg/obj: 0x302a  csc: 0x00.f7883927  itc: 2  flg: E  typ: 2 - INDEX

 

其中最关键的是两点:

1. key overlaps with another :说明索引块内部 key 之间发生重叠,基本可以往逻辑坏块、索引结构异常方向判断。

2. seg/obj: 0x302a :这是定位问题对象的关键。它是十六进制,需要转换成十进制后再去数据库字典里反查。

今天这篇文章,就把这次从 trace 定位对象、十六进制转换、识别 IOT、处理 ORA-28650 、最后重建对象的完整过程整理出来。

现场库名、路径、客户信息都已经脱敏, Oracle 自身对象名保留,因为这是排查逻辑的一部分。

一、故障现象

数据库 open 后,alert 日志中出现类似报错:

Errors in file /u01/oracle/diag/rdbms/<db_unique_name>/<instance_name>/trace/<instance_name>_mmon_<pid>.trc

 

ORA-00600: internal error code, arguments: [6200], [18446744073709551615], [], [], [], [], [], [], [], [], [], []

 

Incident details in:

/u01/oracle/diag/rdbms/<db_unique_name>/<instance_name>/incident/incdir_<incident_id>/<instance_name>_mmon_<pid>_i<incident_id>.trc

 

Use ADRCI or Support Workbench to package the incident.

See Note 411.1 at My Oracle Support for error and packaging details.

 

Exception [type: SIGSEGV, SI_KERNEL(general_protection)]

[ADDR:0x0] [PC:0x2C3793B, kghstack_err()+117]

 

随后又出现:

ORA-07445: exception encountered: core dump [kghstack_err()+117] [SIGSEGV]

ORA-00600: internal error code, arguments: [6200], [18446744073709551615], [], [], [], [], [], [], [], [], [], []

 

这里有几个判断点:

3. 报错进程是 MMON ,不是普通业务会话。

4. ORA-00600 [6200] 是内部错误,需要继续看 incident trace。

5. 第二个参数 18446744073709551615 是 2^64 - 1 ,按无符号 64 位整数看是最大值,很多内部场景里可以理解成一个类似 -1 的特殊标记。排查时不要只盯着这个参数,真正有价值的是 trace 里后面的块校验信息。

这类问题我一般不会直接猜,而是先把 trace 文件打开,把能定位对象的线索找出来。

二、 trace 中真正有用的线索

incident trace 里有这样一段:

**** key (begin=0x14b4, len=983) overlaps with another

 

begin = 0x14de len = 555

 

---- end index block validation

 

Block header dump:  0x00801e55

 

Object id on Block? Y

 

seg/obj: 0x302a  csc: 0x00.f7883927  itc: 2  flg: E  typ: 2 - INDEX

 

brn: 0  bdba: 0x801e50 ver: 0x01 opc: 0

 

先拆一下这段信息:

6. key overlaps with another :索引块内部 key 重叠,这是非常强的索引块逻辑异常信号。

7. typ: 2 - INDEX :块类型是索引块。

8. seg/obj: 0x302a :这个块属于哪个段对象,要靠它定位。

9. Block header dump: 0x00801e55 :这是块地址,也可以进一步拆出 file# 和 block#。

所以排查主线很清晰:

trace 发现索引块异常

   -> 取 seg/obj 十六进制对象号

   -> 转成十进制

   -> 到 DBA_OBJECTS 反查对象

   -> 判断对象类型和所属表

   -> 决定修复方式

 

三、重点补充: 0x302a 怎么转换成十进制?

trace 里的 seg/obj: 0x302a 不能直接拿去查 DBA_OBJECTS 。数据库字典里的 OBJECT_ID 、 DATA_OBJECT_ID 是十进制,所以第一步要把 0x302a 转成十进制。

3.1 手工转换

十六进制的 0x302a ,去掉前缀 0x 后是:

302A

 

十六进制每一位的权重是 16 的幂:

302A

= 3 * 16^3 + 0 * 16^2 + 2 * 16^1 + A * 16^0

= 3 * 4096 + 0 * 256 + 2 * 16 + 10 * 1

= 12288 + 0 + 32 + 10

= 12330

 

所以:

0x302a = 12330

 

3.2 用 Oracle SQL 转换

在数据库里可以直接用 TO_NUMBER 转:

select to_number('302A', 'XXXX') as data_object_id

from dual;

 

输出:

DATA_OBJECT_ID

--------------

12330

 

注意, TO_NUMBER 里不要带 0x 前缀,直接传 302A 即可。

如果想写得更通用一点:

select to_number(replace(upper('0x302a'), '0X', ''), 'XXXX') as data_object_id

from dual;

 

3.3 用操作系统命令转换

如果当时不方便进数据库,也可以在 Linux 上直接转:

printf "%d\n" 0x302a

 

或者用 bc :

echo "ibase=16;302A" | bc

 

输出都是:

12330

 

这个小技巧很实用。遇到 trace 里的 seg/obj 、 rdba 、 bdba 这类十六进制值时,不要凭感觉猜,先转成十进制再查字典。

四、反查问题对象

有了十进制对象号 12330 ,开始查字典。

这里我建议不要只查 OBJECT_ID ,也把 DATA_OBJECT_ID 一起查。因为块头里的 seg/obj 更接近段对象 ID,在对象经历过 truncate、move、重建后, OBJECT_ID 和 DATA_OBJECT_ID 可能不完全一样。

select owner,

        object_name,

        object_type,

        object_id,

        data_object_id

from dba_objects

where object_id = 12330

    or data_object_id = 12330;

 

本次查到:

OWNER  OBJECT_NAME        OBJECT_TYPE  OBJECT_ID  DATA_OBJECT_ID

-----  -----------------  -----------  ---------  --------------

SYS    SYS_IOT_TOP_12329  INDEX        12330      12330

 

对象名是 SYS_IOT_TOP_12329 ,对象类型是 INDEX 。

看到 SYS_IOT_TOP_ 这个前缀,基本就要想到:这不是普通索引,大概率是 IOT(Index Organized Table,索引组织表)的主键索引。

继续查它属于哪张表:

select owner,

        index_name,

        table_owner,

        table_name,

        index_type

from dba_indexes

where owner = 'SYS'

   and index_name = 'SYS_IOT_TOP_12329';

 

输出:

OWNER  INDEX_NAME         TABLE_OWNER  TABLE_NAME       INDEX_TYPE

-----  -----------------  -----------  --------------  ----------

SYS    SYS_IOT_TOP_12329  SYS          AQ$_ALERT_QT_T  IOT - TOP

 

最终定位到问题对象:

SYS.AQ$_ALERT_QT_T

 

这是一个 SYS 下的 AQ 相关内部对象,并且底层是 IOT。

五、补充: RDBA 怎么拆 file# 和 block#?

trace 里还有一个块地址:

Block header dump:  0x00801e55

 

这个值也很有用。它可以转成十进制 RDBA,再拆出相对文件号和块号。

先转十进制:

select to_number('00801E55', 'XXXXXXXX') as rdba_dec

from dual;

 

输出:

RDBA_DEC

--------

8396373

 

再用 DBMS_UTILITY 拆 file# 和 block#:

select dbms_utility.data_block_address_file(

          to_number('00801E55', 'XXXXXXXX')

        ) as file_no,

        dbms_utility.data_block_address_block(

          to_number('00801E55', 'XXXXXXXX')

        ) as block_no

from dual;

 

输出示例:

FILE_NO  BLOCK_NO

-------  --------

2        7765

 

它背后的计算逻辑也不复杂。 Oracle RDBA 中低 22 位表示 block#,高位表示 file#:

2^22 = 4194304

 

file#  = floor(8396373 / 4194304) = 2

block# = mod(8396373, 4194304)    = 7765

 

如果想进一步确认这个块在哪个数据文件里:

select file#,

        name

from v$datafile

where file# = 2;

 

如果需要对单块做进一步检查,也可以用 dbv :

dbv file=/path/to/datafile.dbf blocksize=8192 start=7765 end=7765

 

不过这次 trace 已经明确指向索引块逻辑异常,修复重点不在恢复单个数据块,而在处理对应的 IOT 对象。

六、为什么不能直接 rebuild?

既然定位到的是索引,第一反应通常是重建索引:

alter index SYS.SYS_IOT_TOP_12329 rebuild;

 

但执行后报错:

ORA-28650: Primary index on an IOT cannot be rebuilt

 

这个报错非常关键。

普通堆表的索引坏了,大多数情况下可以 rebuild 。但是 IOT 不一样。IOT 的数据本身就是按照主键存放在 B-tree 结构里的,所谓的主键索引就是表本身的存储结构。

也就是说:

普通表:表段 + 索引段,索引坏了可以单独 rebuild

IOT :主键索引就是表本体,不能像普通索引一样单独 rebuild

 

所以 SYS_IOT_TOP_12329 不能直接 rebuild。要修,就要围绕 IOT 对象本身做处理。

七、先备份问题对象

处理 SYS 下的内部对象,第一原则是:先备份,再动手。

本次先把数据备份出来:

create table SYS.AQ$_ALERT_QT_T_BAK

as

select *

from SYS.AQ$_ALERT_QT_T;

 

建议同时做几项确认:

select count(*) from SYS.AQ$_ALERT_QT_T;

 

select count(*) from SYS.AQ$_ALERT_QT_T_BAK;

 

select owner,

        object_name,

        object_type,

        status

from dba_objects

where owner = 'SYS'

   and object_name in ('AQ$_ALERT_QT_T', 'AQ$_ALERT_QT_T_BAK');

 

如果是生产库,我还会建议在操作前保留:

10. 当前 alert 日志片段。

11. incident trace 文件。

12. DBMS_METADATA.GET_DDL 输出。

13. 备份表行数。

14. 数据库备份或快照恢复手段。

这种 SYS 内部对象处理,不要只留一段命令。后面复盘或者回退时,证据链很重要。

八、获取原对象 DDL

接着抽取原对象 DDL:

select dbms_metadata.get_ddl('TABLE', 'AQ$_ALERT_QT_T', 'SYS')

from dual;

 

脱敏整理后的核心结构如下:

CREATE TABLE "SYS"."AQ$_ALERT_QT_T"

(

   "NEXT_DATE" TIMESTAMP (6),

   "TXN_ID"    VARCHAR2(30),

   "MSGID"     RAW(16),

   "ACTION"    NUMBER,

   PRIMARY KEY ("NEXT_DATE", "TXN_ID", "MSGID") ENABLE

)

USAGE QUEUE ORGANIZATION INDEX

NOCOMPRESS

PCTFREE 10

INITRANS 2

MAXTRANS 255

LOGGING

TABLESPACE "SYSAUX"

PCTTHRESHOLD 50;

 

这里再次确认:它不是普通 heap table,而是:

USAGE QUEUE ORGANIZATION INDEX

 

也就是 AQ 相关的 IOT 结构。

九、直接 drop 为什么失败?

尝试直接删除:

drop table SYS.AQ$_ALERT_QT_T;

 

报错:

ORA-24005: Inappropriate utilities used to perform DDL on AQ table SYS.AQ$_ALERT_QT_T

 

这个错误也符合预期。因为它是 AQ 相关对象,不允许像普通表一样直接用 DDL 工具处理。

标准思路上, AQ queue table 应该优先考虑 DBMS_AQADM 这类包进行管理。但这次是 SYS 内部 AQ 对象异常,并且对象本身已经触发内部错误,现场最终采用了维护窗口下的应急处理方式。

执行前先开启事件:

alter session set events '10851 trace name context forever, level 1';

 

然后删除对象:

drop table SYS.AQ$_ALERT_QT_T;

 

删除后关闭事件:

alter session set events '10851 trace name context off';

 

这里必须强调一句: 10851 这类事件属于非常规处理手段,不适合作为日常操作模板。生产环境动 SYS 内部对象前,建议至少满足几个条件:

15. 有完整备份或快照。

16. 有明确的问题对象定位证据。

17. 操作窗口可控。

18. 已评估对象用途和影响范围。

19. 必要时通过 Oracle Support 确认。

这一步不是 “胆子大就行”,而是要有回退和证据。

十、第一次重建:按 DDL 重建后回灌失败

删除后,按 GET_DDL 抽出的结构尝试重建:

CREATE TABLE "SYS"."AQ$_ALERT_QT_T"

(

   "NEXT_DATE" TIMESTAMP (6),

   "TXN_ID"    VARCHAR2(30),

   "MSGID"     RAW(16),

   "ACTION"    NUMBER,

   PRIMARY KEY ("NEXT_DATE", "TXN_ID", "MSGID") ENABLE

)

USAGE QUEUE ORGANIZATION INDEX

NOCOMPRESS

PCTFREE 10

INITRANS 2

MAXTRANS 255

LOGGING

TABLESPACE "SYSAUX"

PCTTHRESHOLD 50;

 

表创建成功。

但是回灌数据时报错:

insert into SYS.AQ$_ALERT_QT_T

select *

from SYS.AQ$_ALERT_QT_T_BAK;

 

报错:

ORA-12899: value too large for column "SYS"."AQ$_ALERT_QT_T"."ACTION" (actual: 32, maximum: 22)

 

这里很容易让人疑惑: DDL 里 ACTION 是 NUMBER ,为什么会出现 actual: 32, maximum: 22 ?

我的理解是,这类 AQ 内部对象并不是普通业务表,内部列定义、隐藏属性、队列组织方式可能比 GET_DDL 展示出来的内容更复杂。单纯照 DDL 手工重建,未必能完整还原原对象的内部属性。

所以这一步的结论是:手工按 DDL 重建失败,不要硬插、不要改数据,改用更保守的 CTAS 方式保持列定义和数据一致。

十一、第二次处理: CTAS 重建并补主键

重新开启事件后,先删除刚才创建的对象:

alter session set events '10851 trace name context forever, level 1';

 

drop table SYS.AQ$_ALERT_QT_T;

 

这次不再手写列定义,而是直接通过备份表 CTAS 回来:

create table SYS.AQ$_ALERT_QT_T

tablespace SYSAUX

as

select *

from SYS.AQ$_ALERT_QT_T_BAK;

 

然后补回主键:

alter table SYS.AQ$_ALERT_QT_T

add constraint PK_AQ_ALERT_QT_T

primary key ("NEXT_DATE", "TXN_ID", "MSGID");

 

最后关闭事件:

alter session set events '10851 trace name context off';

 

再检查索引:

select table_owner,

        table_name,

        owner,

        index_name,

        status

from dba_indexes

where table_owner = 'SYS'

   and table_name = 'AQ$_ALERT_QT_T';

 

输出类似:

TABLE_NAME       INDEX_NAME          STATUS

--------------   -----------------   ------

AQ$_ALERT_QT_T   PK_AQ_ALERT_QT_T    VALID

 

这时原来那个异常的 SYS_IOT_TOP_12329 已经不再作为坏块对象存在,新的对象结构也能正常查询。

十二、处理后验证

处理 SYS 对象,不能只看命令执行成功。后面验证一定要做完整。

12.1 检查对象状态

select owner,

        object_name,

        object_type,

        status

from dba_objects

where owner = 'SYS'

   and object_name like 'AQ$_ALERT_QT_T%';

 

12.2 检查索引状态

select owner,

        index_name,

        table_owner,

        table_name,

        status

from dba_indexes

where table_owner = 'SYS'

   and table_name = 'AQ$_ALERT_QT_T';

 

12.3 检查是否还有坏块记录

select *

from v$database_block_corruption;

 

如果之前已经定位到 file# 和 block#,也可以用 dbv 对对应数据文件或对应块范围做补充检查。

12.4 观察 alert 日志

tail -f /u01/oracle/diag/rdbms/<db_unique_name>/<instance_name>/trace/alert_<instance_name>.log

 

重点观察:

20. MMON 是否继续报 ORA-00600 [6200] 。

21. 是否还有新的 incident 生成。

22. 是否有新的 ORA-07445 。

23. 数据库 open 后后台进程是否稳定。

如果处理后不再出现新的 incident,相关对象状态正常,业务验证也没问题,基本可以判断本次处理完成。

十三、这次故障的关键点

这次处理过程里,我觉得最值得记住的是下面几个点。

第一, ORA-00600 不要只看 alert 日志,要看 incident trace。真正的定位信息往往在 trace 里的 block dump、stack、object id、rdba 这些细节里。

第二, seg/obj 是定位对象的关键,但它通常是十六进制。比如这次:

seg/obj: 0x302a

0x302a = 12330

 

转换后再查:

select owner, object_name, object_type

from dba_objects

where object_id = 12330

    or data_object_id = 12330;

 

第三, Block header dump: 0x00801e55 这类 RDBA 也很重要。它可以拆出 file# 和 block#,帮助我们确认问题块落在哪个数据文件、哪个块上。

第四, IOT 的主键索引不能按普通索引处理。遇到:

ORA-28650: Primary index on an IOT cannot be rebuilt

 

说明你碰到的不是普通索引 rebuild 问题,而是 IOT 结构本身的问题。

第五, SYS 下 AQ 内部对象要谨慎处理。 ORA-24005 提醒我们:这不是普通表,不应该随便用普通 DDL 操作。现场使用事件绕过属于应急手段,不建议脱离备份和验证直接套用。

十四、总结

这次故障从表面看是:

数据库 open 后 MMON 报 ORA-00600 [6200]

 

但真正的处理路径是:

查看 incident trace

   -> 发现 index block validation 异常

   -> 通过 seg/obj: 0x302a 定位对象

   -> 十六进制转十进制得到 12330

   -> 反查到 SYS_IOT_TOP_12329

   -> 确认属于 SYS.AQ$_ALERT_QT_T

   -> 识别为 AQ 相关 IOT 对象

   -> 普通 rebuild 报 ORA-28650

   -> 备份数据

   -> 维护窗口下删除并重建对象

   -> 回灌数据、补主键、验证对象状态和 alert 日志

 

我一直觉得, DBA 处理故障最重要的不是“命令背得多”,而是能把线索串起来。

ORA-00600 看起来吓人,但只要 trace 里能定位对象、能解释块地址、能判断对象类型,就不是完全无从下手。

这篇文章里补的十六进制转换、 RDBA 拆解、IOT 主键索引不能 rebuild 这些点,都是生产排障里非常实用的小技能。平时不一定天天用,但真遇到内部错误时,往往就是这些细节帮你把问题从“玄学”拉回到“可定位、可验证、可处理”。

好了,今天这篇就到这里。你在生产环境里遇到过 ORA-00600 或索引逻辑坏块吗?是 rebuild 解决的,还是最后走了对象重建、RMAN、Support patch?欢迎在评论区聊聊你的处理经历。

—— 睿 | Oracle性能优化老司机

专注硬核干货,欢迎一起卷技术!

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70047128/viewspace-3179403/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
要得到你想要的某样东西,最可靠的办法是让你自己配得上它。

注册时间:2025-07-21

  • 博文量
    30
  • 访问量
    31690