接受SQL Profile时遇ORA-01422与ORA-06512错误求因
问题分析与解决方案
你遇到的ORA-01422: exact fetch returns more than requested number of rows错误,是调用DBMS_SQLTUNE.ACCEPT_SQL_PROFILE时触发的——核心原因是Oracle SQL调优顾问的内部逻辑中,某个查询原本预期仅返回单行数据,但实际查询到了多条匹配记录,导致程序执行失败。
具体可能的诱因:
- 同名调优任务重复存在:你指定的
task_0123456任务可能在TEST用户下存在多个实例(比如重复创建但未清理的任务),当内部查询该任务相关的profile信息时,返回了多行结果。 - SQL语句存在多版本/绑定变量差异:目标SQL_ID
0yyyyyyy对应的语句可能有多个不同的执行版本(比如绑定变量类型不同、语句文本细微差异但共享了同一个SQL_ID),导致调优顾问生成的profile关联了多条记录,accept时无法定位到唯一对象。 - 数据字典不一致:SQL调优相关的系统表(如
DBA_ADVISOR_TASKS、DBA_SQL_PROFILES)存在脏数据或重复条目,破坏了内部查询的唯一性预期。
验证与解决步骤:
检查并清理重复任务
先查询是否存在同名的重复任务:SELECT task_id, task_name, status, created FROM DBA_ADVISOR_TASKS WHERE task_name = 'task_0123456' AND owner = 'TEST';如果返回多条记录,先删除旧任务:
EXEC DBMS_SQLTUNE.DROP_TUNING_TASK('task_0123456');然后重新创建调优任务(建议让系统自动生成唯一任务名,避免手动命名冲突):
DECLARE l_sql_tune_task_id VARCHAR2(100); BEGIN l_sql_tune_task_id := DBMS_SQLTUNE.create_tuning_task ( sql_id => '0yyyyyyy', scope => DBMS_SQLTUNE.scope_comprehensive, time_limit => 500, description => 'Tuning task1 for statement 0c' ); DBMS_OUTPUT.put_line('l_sql_tune_task_id: ' || l_sql_tune_task_id); END; /改用SQL_ID直接关联接受Profile
尝试跳过任务名的歧义,直接通过SQL_ID来接受profile:BEGIN DBMS_SQLTUNE.accept_sql_profile ( sql_id => '0yyyyyyy', task_owner => 'TEST', replace => TRUE ); END; /检查数据字典一致性
如果上述方法无效,可能是数据字典存在异常,可以执行以下语句验证相关系统表的结构:ANALYZE TABLE SYS.WRI$_ADV_TASKS VALIDATE STRUCTURE CASCADE; ANALYZE TABLE SYS.WRI$_ADV_SQL_PROFILES VALIDATE STRUCTURE CASCADE;如果发现结构异常,建议联系Oracle官方支持进一步排查。
附你提供的原始信息:
错误栈:
begin dbms_sqltune.accept_sql_profile ( task_name => 'task_0123456', task_owner => 'TEST', replace => TRUE ); end; ORA-01422: exact fetch returns more than requested number of rows ORA-06512: at "SYS.DBMS_SQLTUNE_INTERNAL", line 16446 ORA-06512: at "SYS.PRVT_SQLPROF_INFRA", line 31 ORA-06512: at "SYS.DBMS_SQLTUNE", line 7544 ORA-06512: at "SYS.DBMS_SQLTUNE", line 7568 ORA-06512: at line 2
执行步骤:
DECLARE l_sql_tune_task_id VARCHAR2(100); BEGIN l_sql_tune_task_id := DBMS_SQLTUNE.create_tuning_task ( sql_id => '0yyyyyyy', scope => DBMS_SQLTUNE.scope_comprehensive, time_limit => 500, task_name => 'task_0123456', description => 'Tuning task1 for statement 0c'); DBMS_OUTPUT.put_line('l_sql_tune_task_id: ' || l_sql_tune_task_id); END; / EXEC DBMS_SQLTUNE.execute_tuning_task(task_name => 'task_0123456') / select dbms_sqltune.report_tuning_task('task_0123456') from dual /
调优报告:
1- SQL Profile Finding (see explain plans section below)
A potentially better execution plan was found for this statement.
Recommendation (estimated benefit: 99.52%)
- Consider accepting the recommended SQL profile.
execute dbms_sqltune.accept_sql_profile(task_name => 'task_0123456', task_owner => 'TEST', replace => TRUE);
内容的提问来源于stack exchange,提问作者Moudiz
相关产品推荐
相关产品推荐

