ORA-00001 unique constraint violated错误的解决

Oracle主键冲突解决
本文介绍了Oracle数据库中遇到ORA-00001错误时的解决办法,该错误由主键冲突引起。文章提供了禁用唯一约束检查的方法,并探讨了cursor_sharing参数设置对性能的影响。
ORA-00001:  unique  constraint  (PERFSTAT.STATS$SQL_SUMMARY_PK)  violated
ORA-06512:  at  "PERFSTAT.STATSPACK",  line  1361
ORA-06512:  at  "PERFSTAT.STATSPACK",  line  2471
ORA-06512:  at  "PERFSTAT.STATSPACK",  line  91
ORA-06512:  at  line  1
Sun  Oct  16  00:43:39  2005


这个错误此前从未遇到,但是既然是主键冲突,那肯定是存在重复主键的数据。

肯定能暂时解决问题方法就是暂时禁用唯一约束检查:
ALTER  TABLE  PERFSTAT.STATS$SQL_SUMMARY 
MODIFY  CONSTRAINT  STATS$SQL_SUMMARY_PK  DISABLE  NOVALIDATE;

然后观察数据来发现根本问题,最后彻底解决之。

到Metalink搜索了一下,发现存在一个相关Bug,Bug号为:2784796.
在设置了cursor_sharing为similar或者force之后,可能触发此Bug,导致主键冲突。

此bug据说在Oracle10g中已经修正。
   

            怪不得我前天加statpack时老报这个错,于是我随手加多一个字段address来作为唯一索引 
其实从sql优化角度来说。。。cursor_sharing有exact、similar、force三种值的选择,为了减少statement hard parse value,最好是使用绑定变量,如果无法全面改写程序,DBA的另外选择就是调整这个参数.

  完全相同的statement (包含整个statement的內容、大小写完全相同、where条件相同)在执行计划和parsing tree尚未被清除前可以被直接拿來执行,減少了hard parse的次数,但8i以前只能选择force或者exact,force有可能会造成optimizer执行计划选择失当,结果反而造成性能上的灾难,因此通常不用。 

从9i开始多了similar的选择,它具备了2者的优点,当对象表有统计值时,会选择最佳的执行计划,如果没有,就和force一样使用旧的执行计划。 

cursor_sharing=similar的效果就是这样:

如果你有2句sql:
select a1,a2 from t1 where a3=1;
select a1,a2 from t1 where a3=3;

那么oracle会自动转换为:
select a1,a2 from t1 where a3= =:"SYS_B_0";

这样就可以避免硬解析带来的CPU开销,从而提高性能;但是如果这个表做过分析了,则每换一次条件值,就会做一次硬解析,以避免执行计划选择失当的问题。

更详细的分析看这里: http://blog.csdn.net/biti_rainy/archive/2004/07/12/39466.aspx

en... 找时间作个试验,验证一下这段话。看来oracle的确做得越来越不需要dba了,呵呵

还有一篇相关的,讨论是否使用preparedstatment的帖子,贴出来作为参考
http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=121&threadID=10397&start=0&tstart=0
 
 
----这次出现这个错误,是因为数据库中的那个表中有两条重复的数据,所以读取的时候不能产生唯一结果导致的。
解决方法:找到对应表删除重复数据。
<think>我们遇到了一个Oracle数据库错误ORA-00001: unique constraint (YKT.SYS_C00579991) violated。 这个错误意味着我们试图插入或更新一条数据,而这条数据违反了唯一性约束(unique constraint)。约束名为"SYS_C00579991",它属于模式(schema)"YKT"。 唯一性约束要求在该约束所覆盖的列(或列组合)上,所有行的值都必须唯一。当我们试图插入重复的值,或者更新某条记录导致该列的值与其他记录重复时,就会触发这个错误解决方案: 1. 找出违反约束的具体列:首先,我们需要知道是哪个表、哪些列上定义了唯一约束。可以通过查询数据字典视图来获取这些信息。 2. 检查数据:检查我们试图插入或更新的数据,找出重复的值。 3. 处理重复数据:可以选择修改重复的数据,使其变得唯一;或者忽略重复数据的插入(如果业务允许);或者使用MERGE语句来处理(即更新已存在的记录,插入新记录)。 步骤1:查询约束信息 我们可以通过以下SQL查询来获取约束的详细信息: ```sql SELECT owner, constraint_name, table_name, column_name FROM all_cons_columns WHERE constraint_name = 'SYS_C00579991'; ``` 或者,如果当前用户有权限,也可以使用: ```sql SELECT * FROM user_cons_columns WHERE constraint_name='SYS_C00579991'; ``` 假设我们查询到该约束作用于表"YKT"."MY_TABLE"的"MY_COLUMN"列。 步骤2:检查重复数据 如果我们正在插入数据,可以检查即将插入的数据在该列上是否已经存在。例如: ```sql SELECT * FROM YKT.MY_TABLE WHERE MY_COLUMN = '要插入的值'; ``` 步骤3:处理重复的情况 根据业务需求,我们可以选择以下方式之一: a) 如果重复数据是不需要的,则避免插入,并记录日志。 b) 如果重复数据需要被更新,则先更新已有记录,再插入新记录(或者使用MERGE)。 c) 如果业务允许,也可以删除已有的重复记录,再插入新记录(需谨慎)。 例如,在PL/SQL中,我们可以先检查是否存在重复,再决定插入或更新: ```sql DECLARE v_count NUMBER; BEGIN SELECT COUNT(*) INTO v_count FROM YKT.MY_TABLE WHERE MY_COLUMN = '新值'; IF v_count = 0 THEN -- 插入新记录 INSERT INTO YKT.MY_TABLE (COL1, MY_COLUMN) VALUES (val1, '新值'); ELSE -- 更新已有记录 UPDATE YKT.MY_TABLE SET COL1 = val1 WHERE MY_COLUMN = '新值'; END IF; END; / ``` 或者使用MERGE语句(UPSERT操作): ```sql MERGE INTO YKT.MY_TABLE dest USING (SELECT '新值' AS MY_COLUMN, val1 AS COL1 FROM dual) src ON (dest.MY_COLUMN = src.MY_COLUMN) WHEN MATCHED THEN UPDATE SET dest.COL1 = src.COL1 WHEN NOT MATCHED THEN INSERT (dest.MY_COLUMN, dest.COL1) VALUES (src.MY_COLUMN, src.COL1); ``` 注意:MERGE语句需要确保ON条件中的列是唯一约束或主键的列。 另外,如果是在程序代码中,我们可以捕获这个异常并进行相应处理。例如在Java中: ```java try { // 执行插入或更新的代码 } catch (SQLException e) { if (e.getErrorCode() == 1) { // ORA-00001错误代码是1 // 处理违反唯一约束的情况 // 例如,记录日志,或者尝试更新 } else { // 其他异常处理 } } ``` 为了避免这种错误,我们还可以在插入前进行查询,但这样会增加一次数据库查询。在高并发的情况下,可能会遇到竞态条件(即两次查询之间数据被插入),所以最好的方式是在数据库中使用唯一约束,并在应用层捕获异常进行处理。 最后,如果这个错误是在批量操作中发生的,我们需要找出具体是哪一行数据导致了错误,然后对那一行进行单独处理。 总结:违反唯一约束通常是由于插入了重复的值。我们需要定位到重复的列,然后根据业务需求处理重复数据。 §§相关问题§§: 1. 如何查询Oracle数据库中的约束信息? 2. 在Java中如何捕获并处理特定的Oracle错误(如ORA-00001)? 3. 请解释Oracle的MERGE语句的工作原理。 4. 除了唯一约束,Oracle还有哪些常见的约束类型? </think>### 问题分析:ORA-00001: unique constraint violated 这个错误表示在 Oracle 数据库中违反了唯一性约束(unique constraint)。具体分析如下: 1. **约束信息**:`YKT.SYS_C00579991` - `YKT`:约束所在的数据库模式(schema) - `SYS_C00579991`:系统自动生成的唯一约束名称 2. **触发场景**: - 插入或更新数据时,指定列的值与表中已有数据重复 - 批量操作中某条数据违反唯一性约束 3. **根本原因**: - 主键(PRIMARY KEY)或唯一键(UNIQUE KEY)列存在重复值 - 并发操作导致数据冲突 --- ### 解决方案 #### 步骤 1:定位约束对应的表和列 ```sql SELECT a.table_name, a.column_name, a.constraint_name, b.constraint_type FROM all_cons_columns a JOIN all_constraints b ON a.constraint_name = b.constraint_name WHERE a.constraint_name = 'SYS_C00579991' AND a.owner = 'YKT'; ``` **结果示例**: ``` TABLE_NAME | COLUMN_NAME | CONSTRAINT_NAME | CONSTRAINT_TYPE -------------|-------------|-------------------|---------------- EMPLOYEES | EMPLOYEE_ID | SYS_C00579991 | P (主键) 或 U (唯一键) ``` #### 步骤 2:检查重复数据 ```sql -- 查询重复值 SELECT employee_id, COUNT(*) FROM ykt.employees GROUP BY employee_id HAVING COUNT(*) > 1; ``` #### 步骤 3:解决方案(根据业务需求选择) **方案 1:删除重复数据(保留最新记录)** ```sql DELETE FROM ykt.employees WHERE ROWID NOT IN ( SELECT MAX(ROWID) FROM ykt.employees GROUP BY employee_id -- 替换为实际列名 ); ``` **方案 2:更新冲突数据(需明确业务规则)** ```sql -- 例:将冲突的 employee_id 增加后缀 UPDATE ykt.employees SET employee_id = employee_id || '_dup' WHERE employee_id IN ( SELECT employee_id FROM ykt.employees GROUP BY employee_id HAVING COUNT(*) > 1 ); ``` **方案 3:代码层捕获异常(Java 示例)** ```java try (PreparedStatement stmt = conn.prepareStatement( "INSERT INTO employees (employee_id, name) VALUES (?, ?)")) { stmt.setInt(1, 101); stmt.setString(2, "John"); stmt.executeUpdate(); } catch (SQLException e) { if (e.getErrorCode() == 1) { // ORA-00001 错误代码 System.err.println("唯一约束冲突: " + e.getMessage()); // 重试策略:生成新ID/更新数据等 } } ``` --- ### 关键预防措施 1. **事务设计**: ```sql BEGIN SELECT employee_id_seq.NEXTVAL INTO :new_id FROM DUAL; -- 显式获取序列 INSERT INTO employees (...) VALUES (...); COMMIT; ``` 2. **唯一索引监控**: ```sql -- 定期检查索引状态 SELECT index_name, status FROM all_indexes WHERE table_name = 'EMPLOYEES'; ``` 3. **应用层校验**: ```java // Java 预查询示例 public boolean isIdExists(int id) { String sql = "SELECT COUNT(*) FROM employees WHERE employee_id = ?"; try (PreparedStatement stmt = conn.prepareStatement(sql)) { stmt.setInt(1, id); ResultSet rs = stmt.executeQuery(); return rs.next() && rs.getInt(1) > 0; } } ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值