Oracle性能优化-4-SQL优化

前面讲到了索引和提示,指出了优化的工具,而SQL优化的对象,也就是哪些语句需要被优化,这一章将讲明。

4.1查找SQL

4.1.1当前最糟糕的会话

select s.sid,
       m.physical_reads,
       m.cpu,
       m.logical_reads
from   v$sessmetric m,
       v$session    s
where  m.session_id = s.sid
       and m.session_serial_num = s.serial#
       and (m.physical_reads > 100 or m.cpu > 100 or m.logical_reads > 100)
order  by m.physical_reads desc,
          m.cpu            desc,
          m.logical_reads  desc

4.1.2七天内最糟糕的查询

select s.snap_id,
       s.module,
       s.sql_id,
       s.disk_reads_delta,
       s.executions_delta,
       s.disk_reads_delta /
       decode(s.executions_delta, 0, 1, s.executions_delta)
from   dba_hist_sqlstat s
where  s.disk_reads_delta > 10000
order  by s.disk_reads_delta desc;

select *
from   dba_hist_snapshot
where  snap_id = 10006;

  select ds.sql_text
        from   dba_hist_sqltext ds
        where  ds.sql_id = '4rtc18cbwm31v';

4.1.3最耗时的请求

select f.PROGRAM_SHORT_NAME,
       f.PROGRAM,
       f.actual_start_date,
       f.actual_completion_date,
       (f.actual_completion_date - f.actual_start_date) * 24
  from fnd_conc_req_summary_v f
 where (f.actual_completion_date - f.actual_start_date) * 24 > 1
 and f.PROGRAM_APPLICATION_ID=50202
 order by (f.actual_completion_date - f.actual_start_date) * 24 desc

4.2SQL优化建议

4.2.1赋权

如果不赋权只能在system用户下执行操作了

切换到system用户,执行下列语句

grant administer sql tuning set to apps;
grant administer any sql tuning set to apps;
grant advisor to apps;
grant create any sql profile to apps;
grant alter any sql profile to apps;
grant drop any sql profile to apps;

4.2.2创建任务

DECLARE
  tuning_task_name VARCHAR2(240);
  tuning_sqltext   CLOB;
BEGIN
  tuning_sqltext   := 'SELECT prf.full_name,
       prf.person_id
  FROM per_people_f             prf,
       po_agents                poa,
       per_business_groups_perf pbg,
       per_assignments_f        paf_t
 WHERE prf.person_id = poa.agent_id
   AND TRUNC(SYSDATE) BETWEEN prf.effective_start_date AND prf.effective_end_date
   AND TRUNC(SYSDATE) BETWEEN NVL(poa.start_date_active, SYSDATE) AND NVL(poa.end_date_active, SYSDATE)
   AND prf.business_group_id = pbg.business_group_id
   AND SYSDATE BETWEEN paf_t.effective_start_date AND paf_t.effective_end_date
   AND prf.person_id = paf_t.person_id';
  tuning_task_name := dbms_sqltune.create_tuning_task(sql_text    => tuning_sqltext,
                                                      bind_list   => sql_binds(anydata.convertvarchar2(100)),
                                                      user_name   => 'APPS',
                                                      scope       => 'COMPREHENSIVE',
                                                      time_limit  => 60,
                                                      task_name   => 'task2021040',
                                                      description => 'optimize sql');
END;

4.2.3查询任务

select * from user_advisor_log;

4.2.4执行优化

begin
  dbms_sqltune.execute_tuning_task(task_name=>'task2021040');
end;

4.2.5查看优化是否完成

SELECT uat.task_name,
       uat.status
  FROM user_advisor_tasks uat

4.2.6显示优化报告

  select dbms_sqltune.report_tuning_task('task2021040') from dual;

GENERAL INFORMATION SECTION
-------------------------------------------------------------------------------
Tuning Task Name   : task2021040
Tuning Task Owner  : APPS
Workload Type      : Single SQL Statement
Scope              : COMPREHENSIVE
Time Limit(seconds): 60
Completion Status  : COMPLETED
Started at         : 04/06/2021 15:32:50
Completed at       : 04/06/2021 15:32:52

-------------------------------------------------------------------------------
Schema Name: APPS
SQL ID     : 8rt4d4m8jj06h
SQL Text   : SELECT prf.full_name,
                    prf.person_id
               FROM per_people_f             prf,
                    po_agents                poa,
                    per_business_groups_perf pbg,
                    per_assignments_f        paf_t
              WHERE prf.person_id = poa.agent_id
                AND TRUNC(SYSDATE) BETWEEN prf.effective_start_date AND
             prf.effective_end_date
                AND TRUNC(SYSDATE) BETWEEN NVL(poa.start_date_active,
             SYSDATE) AND NVL(poa.end_date_active, SYSDATE)
                AND prf.business_group_id = pbg.business_group_id
                AND SYSDATE BETWEEN paf_t.effective_start_date AND
             paf_t.effective_end_date
                AND prf.person_id = paf_t.person_id

-------------------------------------------------------------------------------
ERRORS SECTION
-------------------------------------------------------------------------------
- ORA-16951: Too many bind variables supplied for this SQL statement.

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

 

看样子绑定变量是必要的,我们在讲索引价值的使用的sql,传入该优化器,看是否能生效

DECLARE
  tuning_task_name VARCHAR2(240);
  tuning_sqltext   CLOB;
BEGIN
  tuning_sqltext   := 'SELECT *
  FROM mtl_system_items_b msi
 WHERE msi.inventory_item_status_code = :A
  ';
  tuning_task_name := dbms_sqltune.create_tuning_task(sql_text    => tuning_sqltext,
                                                      bind_list   => sql_binds(anydata.convertvarchar2(100)),
                                                      user_name   => 'APPS',
                                                      scope       => 'COMPREHENSIVE',
                                                      time_limit  => 60,
                                                      task_name   => 'task2021042',
                                                      description => 'optimize sql');
END;

经过同样的操作,得到如下结果

GENERAL INFORMATION SECTION
-------------------------------------------------------------------------------
Tuning Task Name   : task2021042
Tuning Task Owner  : APPS
Workload Type      : Single SQL Statement
Scope              : COMPREHENSIVE
Time Limit(seconds): 60
Completion Status  : COMPLETED
Started at         : 04/06/2021 15:50:28
Completed at       : 04/06/2021 15:50:30

-------------------------------------------------------------------------------
Schema Name: APPS
SQL ID     : 82nv5hzvns262
SQL Text   : SELECT *
               FROM mtl_system_items_b msi
              WHERE msi.inventory_item_status_code = :A
               

-------------------------------------------------------------------------------
There are no recommendations to improve the statement.

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

看来这个优化器并不是特别智能,而且测试只能绑定一个变量,什么时候拿到一个复杂SQL,再看看效果。

关于函数“dbms_sqltune.create_tuning_task”的用法,请参考https://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_sqltun.htm#CHDGBCDB

4.3SQL自动优化

4.3.1启动优化

system用户下执行

BEGIN
  dbms_auto_task_admin.enable(client_name => 'sql tuning advisor', -- name of the client, as found inDBA_AUTOTASK_CLIENT View.                              
                              operation   => NULL, -- Name of the operation as specified inDBA_AUTOTASK_OPERATION View                      
                              window_name => NULL);
END;

4.3.2修改参数‘’

查询下列SQL

SELECT DAP.parameter_value
  FROM dba_advisor_parameters dap
 WHERE dap.task_name = 'SYS_AUTO_SQL_TUNING_TASK'
 AND DAP.parameter_name='ACCEPT_SQL_PROFILES'

执行下列方法前遇到权限问题,找了一下如何修改密码

添加ORACLE_HOME = <Oracle installation Directory>环境变量
打开命令提示符
将目录更改为 %ORACLE_HOME%\bin
输入命令 sqlplus /nolog
SQL> connect /as sysdba
SQL> alter user SYS identified by newpassword;


参考:https://stackoverflow.com/questions/740119/default-passwords-of-oracle-11g

执行需要sys用户,而输入sys用户登录时,会报错ORA-01031

oracle数据库只允许本地系统上连接DBA,将任意用户添加到DBA组,则该用户则可以作为SYSDBA连接ORACLE,无需指定用户名/密码

我们使用groups命令查看oracle用户所在的组,关于groups命令参考https://blog.csdn.net/qq_34153210/article/details/107166040

因为oracle用户所在的组含有dba,则可以连接sysdba

可以看到我们成功以sys用户登录

然后执行下列方法,将parameter为'ACCEPT_SQL_PROFILES'的值改为true

我们再次执行上面的查询

成功修改

可是用sqlplus输入命令太麻烦了,如果我们要用PLSQL DEVELOPER登录,就需要密码文件这个东西。

首先确认下面的值为exclusive

创建密码文件

以oracle用户执行下列语句

orapwd file=orapw$ORACLE_SID password=bar entries=20

接着去$ORACLE_HOME/dbs 路径下查看是否产生了orapw($ORACLE_SID).ora文件

这时我们就可以在PLSQL/dev软件上使用sys/bar进入sysdba

同样可以执行下面语句

BEGIN
  dbms_sqltune.set_tuning_task_parameter(task_name => 'SYS_AUTO_SQL_TUNING_TASK',
                                         parameter => 'ACCEPT_SQL_PROFILES',
                                         VALUE     => 'TRUE');
END;

最后我们可以将apps也赋予sysdba权限(正式环境不要这么做)

在sys用户下执行

grant sysdba to apps

这样apps用户也拥有了sysdba权限,比如这样

4.3.3执行任务

sysdba下执行

BEGIN
  dbms_sqltune.execute_tuning_task(task_name => 'SYS_AUTO_SQL_TUNING_TASK');
END;

4.3.3查看优化结果

DECLARE

  p_report CLOB;
  PROCEDURE print_clob_data(p_clob IN CLOB) IS
    l_off INTEGER := 1;
    l_amt INTEGER := 4096;
    l_str VARCHAR2(4096);
  
  BEGIN
    LOOP
      dbms_lob.read(p_clob, l_amt, l_off, l_str); --将p_clob 数据从 l_off位置 取出l_amt长度,放入 l_str 中
      l_off := l_off + l_amt; --移动位置
      dbms_output.put_line(l_str);
    
    END LOOP;
  EXCEPTION
    WHEN OTHERS THEN
      NULL;
  END;
BEGIN
  p_report := dbms_sqltune.report_auto_tuning_task(begin_exec   => NULL,
                                                   end_exec     => NULL,
                                                   TYPE         => dbms_sqltune.type_text,
                                                   LEVEL        => dbms_sqltune.level_typical,
                                                   section      => dbms_sqltune.section_all,
                                                   object_id    => NULL,
                                                   result_limit => NULL);

  print_clob_data(p_report);
END;

查看输出看到了这一段

这不是我们在讲hint的时候写的SQL语句吗

看到这一段,新的执行计划提升了100硬盘读取,99.84%内存读取

告诉我们使用唯一性索引,作为新的执行计划,将会大大提高运行效率

4.3.4应用优化

BEGIN
  dbms_stats.gather_table_stats(ownname          => 'INV',
                                tabname          => 'MTL_SYSTEM_ITEMS_B',
                                estimate_percent => dbms_stats.auto_sample_size,
                                method_opt       => 'FOR ALL COLUMNS SIZE AUTO');
END;

发现full hint被优化器否决了

4.4SAP性能分析器

4.4.1建立测试环境

create table object_tab as  select * from dba_objects;

4.4.2收集统计信息

BEGIN
  dbms_stats.gather_table_stats(ownname => 'APPS', tabname => 'OBJECT_TAB', cascade => TRUE);
END;

4.4.3清空内存共享池

alter system flush shared_pool;

4.4.4执行查询

select count(*) from object_tab ot where ot.object_id=100;
select count(*) from object_tab ot where ot.object_id<100;
select count(*) from object_tab ot where ot.object_id=1000;
select count(*) from object_tab ot where ot.object_id<1000;

4.4.5创建优化集

begin
  dbms_sqltune.create_sqlset(sqlset_name=>'sql_replay_test');
end;

4.4.6加载优化集

DECLARE
  l_cursor dbms_sqltune.sqlset_cursor;
BEGIN
  OPEN l_cursor FOR
    SELECT VALUE(a)
      FROM TABLE(dbms_sqltune.select_cursor_cache(basic_filter   => 'sql_text like''%object_tab%'' and parsing_schema_name=''APPS''',
                                                  attribute_list => 'ALL')) a;
  dbms_sqltune.load_sqlset(sqlset_name => 'sql_replay_test', populate_cursor => l_cursor);

END;

4.4.7查询优化集

select sql_text from dba_sqlset_statements dss where dss.sqlset_name='sql_replay_test';

4.4.8输出优化集

DECLARE
  v_task VARCHAR2(64);
BEGIN
  v_task := dbms_sqlpa.create_analysis_task(sqlset_name => 'sql_replay_test');
  dbms_output.put_line(v_task);

END;

这里v_task返回值是TASK_44948,将会传入下面的分析任务中

4.4.9执行分析任务

BEGIN
  dbms_sqlpa.execute_analysis_task(task_name      => 'TASK_44948',
                                   execution_type => 'test execute',
                                   execution_name => 'before_change');
END;

4.4.10查看分析结果

SELECT dbms_sqlpa.report_analysis_task('TASK_44948')
  FROM dual;

我们看看sql_id=7yxbuat00zf0y对于哪条SQL语句

结果为空,是因为上面的语句是我昨天执行的,只能从历史SQL里去找了

  SELECT to_char(substr(ds.sql_text,1,4000)) sql_text,
              ds.sql_id
         FROM dba_hist_sqltext ds
        WHERE ds.sql_text LIKE '%select count(*) from object_tab%'

对应我们第三行的sql_id

这里我们插入一点,我们测试一下这个分析任务和dbms_xplan的异同,下面记录一下XPLAN的输出结果。

1.执行sql语句

select count(*) from object_tab ot where ot.object_id<101

2.启用XPLAN

SELECT t.*
  FROM v$sql s,
       table(DBMS_XPLAN.DISPLAY_CURSOR(s.sql_id, s.child_number)) t
 WHERE sql_text LIKE '%count(*) from object_tab ot where ot.object_id<101%';

4.4.11增加索引

 create index object_tab_n1 on object_tab(object_id)

4.4.12收集统计信息

 begin
 dbms_stats.gather_table_stats('APPS','OBJECT_TAB',cascade=>true);
 end;

4.4.13执行分析任务

BEGIN
  dbms_sqlpa.execute_analysis_task(task_name      => 'TASK_44948',
                                   execution_type => 'test execute',
                                   execution_name => 'after_change');
END;

4.4.14输出结果

SELECT dbms_sqlpa.report_analysis_task('TASK_44948')
  FROM dual;

大大减少了CPU读取,内存占用

这么看不太直关,我们对比看

4.4.15执行分析任务比较

BEGIN
  dbms_sqlpa.execute_analysis_task(task_name        => 'TASK_44948',
                                   execution_type   => 'compare performance',
                                   execution_params => dbms_advisor.arglist('execution_name1',
                                                                            'before_change',
                                                                            'execution_name2',
                                                                            'after_change'));
END;

 4.4.16查看对比输出结果

SELECT dbms_sqlpa.report_analysis_task('TASK_44948')
  FROM dual;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值