ORA-00600是Oracle数据库的内部错误,其中[12807]是一个特定的错误代码,表示CON$约束基表的CON#序列号已达到上限。这个错误会导致无法创建任何新表、临时表或约束,严重影响数据库的正常运行。本文将详细介绍该错误的原因、诊断方法和解决方案。
一、错误概述
1.1 错误信息
ORA-00600: internal error code, arguments: [12807], [], [], [], [], [], [], []
1.2 错误影响
当遇到此错误时,数据库会出现以下症状:
- ❌ 无法创建新表(CREATE TABLE失败)
- ❌ 无法创建临时表
- ❌ 无法添加约束(PRIMARY KEY、FOREIGN KEY、CHECK等)
- ❌ 任何隐式创建约束的操作都会失败
- ⚠️ 应用程序报错,业务受阻
1.3 常见触发场景
该错误常见于以下环境:
- 金蝶EAS系统
- 金蝶HR系统
- 运行时间很长的OLTP数据库
- 频繁创建/删除临时表的应用
- 大量使用动态SQL创建对象的系统
二、错误原因深度分析
2.1 CON$表是什么?
CON$是Oracle数据字典中的一个基表,用于存储数据库中所有约束的元数据信息。每当创建一个约束时,Oracle会在CON$表中插入一条记录,并分配一个唯一的CON#序列号。
-- 查看CON$表结构
DESC sys.con$
-- 主要字段
-- CON# : 约束的内部序列号(关键字段)
-- NAME : 约束名称
-- OWNER# : 约束所属用户ID
2.2 为什么CON#会耗尽?
CON#是一个32位整数,理论上限约为21亿(2^31)。但在某些情况下,这个序列号会异常快速增长:
| 原因 | 说明 |
|---|---|
| Bug 13784384 | Oracle已知Bug,导致CON#序列号异常递增 |
| 频繁创建/删除约束 | 即使约束被删除,CON#不会被重用 |
| 临时表滥用 | 频繁创建临时表及其约束 |
| 动态DDL | 应用程序大量执行动态CREATE TABLE |
| 长期运行 | 数据库运行多年,累积消耗 |
2.3 相关Bug信息
Bug 13781691:ORA-600 [12807] if CON$.CON# very high due to bug 13784384
| 项目 | 说明 |
|---|---|
| 产品 | Oracle Server (RDBMS) |
| 受影响版本 | 10.2.0.5, 11.1.0.7, 11.2.0.2, 11.2.0.3 |
| 修复版本 | 11.2.0.4, 12.1.0.1及以上 |
| 平台 | 所有平台 |
Bug修复说明:该修复提高了CON#的上限。但Oracle强调,必须同时找出导致CON#快速增长的根本原因,否则可能再次触及新的上限。
三、诊断方法
3.1 确认当前CON#值
-- 查看当前最大CON#值
SELECT MAX(con#) AS max_con_id FROM sys.con$;
-- 查看CON$表记录数
SELECT COUNT(*) AS total_constraints FROM sys.con$;
-- 查看CON#分布情况
SELECT
TRUNC(con#/100000000) * 100000000 AS range_start,
COUNT(*) AS cnt
FROM sys.con$
GROUP BY TRUNC(con#/100000000)
ORDER BY 1;
3.2 检查CON#增长速度
-- 查看最近创建的约束(需要有审计或历史数据)
SELECT owner, constraint_name, constraint_type, table_name, last_change
FROM dba_constraints
WHERE last_change > SYSDATE - 7
ORDER BY last_change DESC;
-- 按用户统计约束数量
SELECT
u.username,
COUNT(*) AS constraint_count
FROM sys.con$ c, sys.user$ u
WHERE c.owner# = u.user#
GROUP BY u.username
ORDER BY constraint_count DESC;
3.3 识别约束消耗大户
-- 查看哪些Schema创建了最多约束
SELECT
owner,
constraint_type,
COUNT(*) AS cnt
FROM dba_constraints
GROUP BY owner, constraint_type
ORDER BY cnt DESC;
-- 查看系统生成的约束(SYS_C开头)
SELECT owner, COUNT(*) AS sys_constraint_count
FROM dba_constraints
WHERE constraint_name LIKE 'SYS_C%'
GROUP BY owner
ORDER BY sys_constraint_count DESC;
3.4 检查是否受Bug影响
-- 查看数据库版本
SELECT * FROM v$version WHERE banner LIKE 'Oracle%';
-- 检查是否安装了修复补丁
SELECT * FROM dba_registry_sqlpatch WHERE patch_id IN (13781691, 13784384);
-- 或使用opatch检查
-- $ $ORACLE_HOME/OPatch/opatch lspatches | grep -E "13781691|13784384"
四、解决方案
4.1 方案一:安装Oracle补丁(推荐)
这是Oracle官方推荐的解决方案:
需要的补丁:
- Patch 13781691:提高CON#上限
- Patch 13784384:修复CON#异常递增的根本原因
- Patch 25343563:使CON#可重用(更彻底的解决方案)
升级路径:
- 升级到11.2.0.4或更高版本
- 升级到12c/19c/21c等长期支持版本
# 检查补丁冲突
$ORACLE_HOME/OPatch/opatch prereq CheckConflictAgainstOHWithDetail -ph ./
# 应用补丁(需要停机)
$ORACLE_HOME/OPatch/opatch apply
# 验证补丁
$ORACLE_HOME/OPatch/opatch lspatches
4.2 方案二:数据库逻辑重建
对于无法打补丁的情况,可以通过重建数据库来重置CON#序列:
# 1. 完整导出数据库
expdp system/password \
FULL=Y \
DIRECTORY=backup_dir \
DUMPFILE=full_export_%U.dmp \
LOGFILE=full_export.log \
PARALLEL=4
# 2. 创建新数据库(使用DBCA)
dbca -silent -createDatabase \
-templateName General_Purpose.dbc \
-gdbName newdb \
-sid newdb \
-characterSet AL32UTF8
# 3. 导入数据到新数据库
impdp system/password \
FULL=Y \
DIRECTORY=backup_dir \
DUMPFILE=full_export_%U.dmp \
LOGFILE=full_import.log \
PARALLEL=4
⚠️ 注意:数据库重建是一个重大操作,需要充分的停机窗口和测试验证。建议在非业务高峰期进行。
4.3 方案三:手动重置CON#(高风险)
这是一个非常规方法,仅在紧急情况下由专业人员操作:
-- ⚠️ 警告:此操作风险极高,可能导致数据字典损坏
-- 仅供参考,不建议在生产环境直接执行
-- 必须有完整备份
-- 1. 以SYSDBA身份连接
CONNECT / AS SYSDBA
-- 2. 启动到受限模式
STARTUP RESTRICT
-- 3. 查看当前CON#序列(内部操作,需要Oracle支持指导)
-- 此处省略具体步骤,因为直接操作数据字典基表可能导致严重问题
-- 4. 重新启动数据库
SHUTDOWN IMMEDIATE
STARTUP
强烈建议:方案三涉及直接操作数据字典,可能导致数据库无法启动或数据损坏。请联系Oracle Support或专业数据库恢复团队处理。
五、预防措施
5.1 监控CON#使用情况
-- 创建监控脚本,定期检查CON#值
CREATE OR REPLACE PROCEDURE check_con_usage AS
v_max_con NUMBER;
v_threshold NUMBER := 2000000000; -- 20亿警戒线
BEGIN
SELECT MAX(con#) INTO v_max_con FROM sys.con$;
IF v_max_con > v_threshold THEN
-- 发送告警(可集成邮件或其他告警系统)
DBMS_OUTPUT.PUT_LINE('警告: CON# 已达到 ' || v_max_con || ',接近上限!');
END IF;
END;
/
-- 定期执行检查
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'CHECK_CON_USAGE_JOB',
job_type => 'STORED_PROCEDURE',
job_action => 'CHECK_CON_USAGE',
start_date => SYSTIMESTAMP,
repeat_interval => 'FREQ=DAILY; BYHOUR=8',
enabled => TRUE
);
END;
/
5.2 规范约束命名
避免使用系统生成的约束名(SYS_C开头),显式命名所有约束:
-- 不推荐:让系统生成约束名
CREATE TABLE bad_example (
id NUMBER PRIMARY KEY,
name VARCHAR2(100) NOT NULL
);
-- 推荐:显式命名约束
CREATE TABLE good_example (
id NUMBER CONSTRAINT pk_good_example PRIMARY KEY,
name VARCHAR2(100) CONSTRAINT nn_good_example_name NOT NULL
);
5.3 优化应用设计
- 避免频繁创建/删除临时表
- 使用全局临时表(GTT)替代动态创建的临时表
- 减少不必要的动态DDL操作
- 定期清理不再使用的约束和表
5.4 保持数据库版本更新
- 及时应用Oracle安全补丁和修复补丁
- 规划升级到长期支持版本(如19c)
- 关注Oracle Known Issues和Bug修复公告
六、金蝶EAS/HR系统特别说明
金蝶EAS和HR系统是该错误的常见触发环境,原因包括:
- 系统运行时间长,累积创建大量约束
- 应用层面可能存在频繁的DDL操作
- 系统更新和补丁可能引入新的表和约束
针对金蝶系统的建议:
- 联系金蝶技术支持确认是否有应用层面的优化方案
- 在Oracle层面应用相关补丁
- 考虑在维护窗口进行数据库重建
- 建立CON#监控机制,提前预警
七、快速恢复服务
对于以下情况,诗檀软件提供快速恢复服务:
- 特别大的数据库(TB级别)
- 停机时间窗口很短
- 业务关键型系统
- 缺乏专业DBA团队
我们的服务包括:
- 远程诊断和方案制定
- 补丁应用和升级指导
- 数据库在线重建
- 紧急故障恢复
总结
ORA-00600 [12807]错误虽然是Oracle内部错误,但有明确的原因和解决方案:
- 根本原因:CON$表的CON#序列号达到上限
- 诱发因素:Oracle Bug、频繁DDL、长期运行
- 推荐方案:安装Oracle补丁(13781691、25343563)
- 备选方案:数据库逻辑重建
- 预防措施:监控CON#、规范设计、保持版本更新