这篇文章主要介绍通过dbms_sqldiag来解决与SQL相关的各种问题。dbms_sqldiag是与标准版本数据库软件一起发布,使用它并不需要额外的许可。
dbms_sqldiag可以用于以下问题类型的诊断:
.problem_type_performance 怀疑是性能问题
.problem_type_wrong_results 怀疑查询返回了不一致的结果
.problem_type_compilation_error 在编译时的错误
.problem_type_execution_error 在执行时的错误
诊断problem_type_performance
执行查询并将该语句来作为诊断的SQL语句
SQL> set timing on SQL> set autotrace traceonly SQL> select * from t1 where c1=500000; Elapsed: 00:00:03.43 Execution Plan ---------------------------------------------------------- Plan hash value: 3617692013 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 3 | 5 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| T1 | 1 | 3 | 5 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(TO_NUMBER("C1")=500000) Statistics ---------------------------------------------------------- 1 recursive calls 0 db block gets 1646 consistent gets 0 physical reads 0 redo size 420 bytes sent via SQL*Net to client 419 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed SQL> select sql_text,sql_id from v$sqlarea where sql_text like 'select * from t1 where c1=500000'; SQL_TEXT SQL_ID -------------------------------------------------------------------------------- ------------- select * from t1 where c1=500000 456naq6s2fcpq
创建诊断任务
SQL> set echo on SQL> set linesize 132 SQL> set pagesize 999 SQL> set long 999999 SQL> set serveroutput on SQL> declare 2 v_sql_diag_task_id varchar2(100); 3 begin 4 -- 5 -- create diagnostic task 6 -- 7 v_sql_diag_task_id := dbms_sqldiag.create_diagnosis_task ( 8 sql_id=>'456naq6s2fcpq', 9 problem_type => dbms_sqldiag.problem_type_performance, 10 time_limit => 900, 11 task_name => 'problem_type_performance_task' ); 12 -- 13 -- setup parameters for the task to give verbose output 14 -- 15 dbms_sqltune.set_tuning_task_parameter(v_sql_diag_task_id,'_sqldiag_finding_mode',dbms_sqldiag.sqldiag_findings_filter_plans); 16 end; 17 / PL/SQL procedure successfully completed.
有时sql_id因为一些原因可能在v$sql视图中找不到,因此在这时就需要使用sql_text来代替sql_id,用户想要执行诊断任务必须至少有advisor权限。task_name作为唯一键使用并且在相同用户使用相同任务名之前必须要删除。
检查任务是否创建成功
SQL> select distinct owner, task_name, advisor_name from dba_advisor_tasks where advisor_name ='SQL Repair Advisor' and task_name like '%perf%'order by 1; OWNER TASK_NAME ADVISOR_NAME ------------------------------ ------------------------------ ------------------------------ SYS problem_type_performance_task SQL Repair Advisor
执行论断任务
SQL> exec dbms_sqldiag.execute_diagnosis_task (task_name => 'problem_type_performance_task' ); PL/SQL procedure successfully completed.
生成报告
SQL> select dbms_sqldiag.report_diagnosis_task ('problem_type_performance_task' ) as recommendations from dual; RECOMMENDATIONS -------------------------------------------------------------------------------- GENERAL INFORMATION SECTION ------------------------------------------------------------------------------- Tuning Task Name : problem_type_performance_task Tuning Task Owner : SYS Workload Type : Single SQL Statement Scope : COMPREHENSIVE Time Limit(seconds): 900 Completion Status : COMPLETED Started at : 05/30/2016 10:20:17 Completed at : 05/30/2016 10:20:22 ------------------------------------------------------------------------------- Schema Name: SYS SQL ID : 456naq6s2fcpq SQL Text : select * from t1 where c1=500000 ------------------------------------------------------------------------------- No SQL patch was found to resolve the problem. -------------------------------------------------------------------------------
这上面的这个例子中,没有得到任何patch建议。然而,如果得到了patch,可以执行以下命令来接受patch
begin dbms_sqldiag.accept_sql_patch( task_name =>'problem_type_performance_task', task_owner => 'sys', replace => true); end;
验证SQL Patch是否启用
SQL> SELECT name, status FROM dba_sql_patches WHERE name LIKE '%SYS%'; NAME STATUS ------------------------------ -------- SYS_SQLPTCH_ ENABLED
删除任务
SQL> exec dbms_sqldiag.drop_diagnosis_task('problem_type_performance_task'); PL/SQL procedure successfully completed. SQL> select distinct owner, task_name, advisor_name 2 from dba_advisor_tasks where advisor_name ='SQL Repair Advisor' and task_name like '%perf%'order by 1; OWNER TASK_NAME ADVISOR_NAME ------------------------------ ------------------------------ ------------------------------
删除SQL Patch
--- find the name of the sql patch --- select name, status from dba_sql_patches where name like '%sys%'; ---drop the sql patch. ---replace following patch name with actual name of the sql patch --- from previous query output. exec dbms_sqldiag.drop_sql_patch (name=> 'sys_sqlptch_'); --- verify that the sql patch has been dropped. select name, status from dba_sql_patches where name like '%sys%';
诊断problem_type_wrong_results
创建两个测试表
SQL> create table a_test 2 ( 3 id number not null, 4 clss number not null 5 ); Table created. SQL> create table as_test 2 ( 3 as_id number 4 ); Table created. SQL> insert into a_test values(11,5); 1 row created. SQL> insert into a_test values(1,5); 1 row created. SQL> insert into as_test values(11); 1 row created. SQL> commit; Commit complete.
错误结果--返回0行记录
SQL> select 'working' as is_working,id from a_test a, 2 3 as_test asi 4 where a.id=asi.as_id(+) 5 and a.clss in (1,3,4,5) 6 and a.clss = '5'; IS_WORK ID ------- ---------- SQL> select sql_id, sql_text from v$sql where sql_text like 'select%as is_working%'; SQL_ID SQL_TEXT ------------- -------------------------------------------------------------------------------- 9a15z3d14krcm select 'working' as is_working,id from a_test a, as_test asi where a.i
正确结果--返回2行记录
SQL> select 'working' as is_working,id from a_test a, 2 3 as_test asi 4 where a.id=asi.as_id(+) 5 and a.clss in (1,3,4,5) 6 and a.clss = '5'; IS_WORK ID ------- ---------- working 11 working 1
SQL> set echo on lines 132 pages 999 long 20000 serveroutput on; SQL> declare 2 l_sql_diag_task_id varchar2(100); 3 4 begin 5 -- 6 -- create diagnostic task 7 -- 8 l_sql_diag_task_id := dbms_sqldiag.create_diagnosis_task ( 9 sql_id => '9a15z3d14krcm', 10 problem_type => dbms_sqldiag.problem_type_wrong_results, 11 task_name => 'test_wr_diagnostic_task' ); 12 13 -- 14 -- setup parameters for the task to give verbose output 15 -- 16 dbms_sqltune.set_tuning_task_parameter( 17 l_sql_diag_task_id, 18 '_sqldiag_finding_mode', 19 dbms_sqldiag.sqldiag_findings_filter_plans); 20 end; 21 / PL/SQL procedure successfully completed. SQL> exec dbms_sqldiag.execute_diagnosis_task ( task_name => 'test_wr_diagnostic_task'); PL/SQL procedure successfully completed. SQL> select dbms_sqldiag.report_diagnosis_task ('test_wr_diagnostic_task') as recommendations from dual; RECOMMENDATIONS -------------------------------------------------------------------------------- GENERAL INFORMATION SECTION ------------------------------------------------------------------------------- Tuning Task Name : test_wr_diagnostic_task Tuning Task Owner : SYS Workload Type : Single SQL Statement Scope : COMPREHENSIVE Time Limit(seconds): 1800 Completion Status : COMPLETED Started at : 05/30/2016 10:46:22 Completed at : 05/30/2016 10:46:24 ------------------------------------------------------------------------------- Schema Name: SYS SQL ID : 9a15z3d14krcm SQL Text : select 'working' as is_working,id from a_test a, as_test asi where a.id=asi.as_id(+) and a.clss in (1,3,4,5) and a.clss = '5' ...省略...
诊断PROBLEM_TYPE_COMPILATION_ERROR & PROBLEM_TYPE_EXECUTION_ERROR
创建诊断任务
set echo on set linesize 132 set pagesize 999 set long 999999 set serveroutput on declare v_sql_diag_task_id varchar2(100); begin --- --- create a diagnostic task. use any name you want under task_name argument. --- v_sql_diag_task_id := dbms_sqldiag.create_diagnosis_task ( sql_text => 'select distinct min(src.cf_table_group) from ( select pc.cf_table_group, min(pc.cf_prg_next_run) from testcase1 pc where nvl(pc.cf_prg_next_run, sysdate) < = sysdate group by pc.cf_table_group order by nvl(min(pc.cf_prg_next_run),sysdate) ) src', problem_type => dbms_sqldiag.problem_type_execution_error, time_limit => 3600, task_name => 'error_diagnostic_task' ); -- -- setup parameters for the task to give verbose output -- dbms_sqltune.set_tuning_task_parameter(v_sql_diag_task_id,'_sqldiag_finding_mode',dbms_sqldiag.sqldiag_findings_filter_plans); end;
执行诊断任务
exec dbms_sqldiag.execute_diagnosis_task ( task_name => 'error_diagnostic_task' );
生成报告
set long 9999999 select dbms_sqldiag.report_diagnosis_task ('error_diagnostic_task' ) as recommendations from dual; recommendations -------------------------------------------------------------------------------- general information section ------------------------------------------------------------------------------- tuning task name : error_diagnostic_task tuning task owner : tc2533 workload type : single sql statement scope : comprehensive time limit(seconds): 3600 completion status : completed started at : 10/27/2011 22:35:07 completed at : 10/27/2011 22:35:07 ------------------------------------------------------------------------------- schema name: tc2533 sql id : 4k1tdq940wvpk sql text : select distinct min(src.cf_table_group) from ( select pc.cf_table_group, min(pc.cf_prg_next_run) from testcase1 pc where nvl(pc.cf_prg_next_run, sysdate) < = sysdate group by pc.cf_table_group order by nvl(min(pc.cf_prg_next_run),sysdate) ) src ------------------------------------------------------------------------------- findings section (1 finding) ------------------------------------------------------------------------------- 1- sql patch finding (see explain plans section below) ------------------------------------------------------ a potentially better execution plan was found for this statement. recommendation -------------- - consider accepting the recommended sql patch. execute dbms_sqldiag.accept_sql_patch(task_name => 'error_diagnostic_task', task_owner => 'tc2533', replace => true); rationale --------- recommended plan with hash value 3673393522 has number of rows 1, check sum 2342552567, execution time 0 and 6 buffer gets
接受建议
execute dbms_sqldiag.accept_sql_patch(task_name =>'error_diagnostic_task', task_owner => 'tc2533', replace => true);
删除诊断任务
exec dbms_sqldiag.drop_diagnosis_task ( task_name => 'error_diagnostic_task' );