阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Automatic的SQL Profile来稳定执行计划

445次阅读
没有评论

共计 14915 个字符,预计需要花费 38 分钟才能阅读完成。

我们都希望 Oracle 数据库的执行的 SQL,CBO 都能够产生正确的执行计划,但是事实上由于各种原因(例如 SQL 所对应的对应的统计信息不准确,或者 CBO 内部一些计算公式的缺陷等),导致了 CBO 会产生效率不高的,甚至是错误的执行计划。特别是 CBO 对目标 SQL 所产生的初始执行计划是正确的,后来由于各种原因(比如统计信息的变更),导致了 CBO 重新产生了一个错误的执行计划,这种执行计划的改变往往会导致目标 SQL 执行时间呈一个数量级的递增,而且通常会给我们造成一个困惑,一条 SQL 原本可以正常的运行,但是为什么会突然变得很慢?其实这种 SQL 执行效率突然的衰减往往是因为目标 SQL 执行计划的改变。这时候我们可以使用 SQL_Profile 或者 SPM 来解决执行计划变更的问题,用他们来调整稳定目标的 SQL 执行计划。下面进行一个 Automatic 的 SQL Profile 来稳定执行计划的实验。

1. 创建一个测试表并插入数据,并创建相对应的索引
SQL> create table t1(n number);

 Table created.

 SQL> declare
  2  begin
  3  for i in 1 .. 10000
  4  loop
  5  insert into t1 values(i);
  6  commit;
  7  end loop;
  8  end;
  9  /

 PL/SQL procedure successfully completed.

 SQL> select count(*) from t1;

  COUNT(*)
 ———-
      10000

 SQL> create index idx_t1 on t1(n);

 Index created.

 2. 对表 T1 收集统计信息

SQL> exec dbms_stats.gather_table_stats(ownname =>’SYS’,tabname =>’T1′,method_opt =>’for all columns size 1′,CASCADE =>true);

 PL/SQL procedure successfully completed.

 3. 使用 hint 强制不使用索引,来模拟那些执行计划错误的 SQL,并查看执行计划。
SQL> select /*+ no_index(t1 idx_t1) */ * from t1 where n=1;

 N
 ———-
 1

 SQL> select * from table(dbms_xplan.display_cursor(null,null,’advanced’));

 PLAN_TABLE_OUTPUT
 ——————————————————————————–
 SQL_ID 1kg76709mx29d, child number 0
 ————————————-
 select /*+ no_index(t1 idx_t1) */ * from t1 where n=1

 Plan hash value: 3617692013

 ————————————————————————–
 | Id  | Operation  | Name | Rows  | Bytes | Cost (%CPU)| Time |
 ————————————————————————–
 |  0 | SELECT STATEMENT  | | | |    7 (100)| |
 |*  1 |  TABLE ACCESS FULL| T1 |    1 |    4 |    7  (0)| 00:00:01 |

 PLAN_TABLE_OUTPUT
 ——————————————————————————–
 ————————————————————————–

 Query Block Name / Object Alias (identified by operation id):
 ————————————————————-

    1 – SEL$1 / T1@SEL$1

 Outline Data
 ————-

  /*+

 PLAN_TABLE_OUTPUT
 ——————————————————————————–
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE(‘11.2.0.4’)
      DB_VERSION(‘11.2.0.4’)
      ALL_ROWS
      OUTLINE_LEAF(@”SEL$1″)
      FULL(@”SEL$1″ “T1″@”SEL$1”)
      END_OUTLINE_DATA
  */

 Predicate Information (identified by operation id):

 PLAN_TABLE_OUTPUT
 ——————————————————————————–
 —————————————————

    1 – filter(“N”=1)

 Column Projection Information (identified by operation id):
 ———————————————————–

    1 – “N”[NUMBER,22]

 42 rows selected.

从上面的内容我们不难发现,这条 sql 语句所走的是全表扫描,但是这显然是个错误的执行计划,正确的执行计划,我们应该是走索引。

 我们现在使用 SQL Tuning Advisor 来尝试对这条 SQL 进行通过产生 Automatic 类型的 SQL Profile

 4. 创建一个名为 my_sql_tuning_task2 的自动调整任务

SQL> declare
  2  my_task_name varchar2(30);
  3  my_sqltext CLOB;
  4  BEGIN
  5  my_sqltext :=’select /*+ no_index(t1 idx_t1) */ * from t1 where n=1′;
  6  my_task_name := dbms_sqltune.create_tuning_task(
  7  sql_text => my_sqltext,
  8  user_name => ‘SYS’, 
  9  scope => ‘COMPREHENSIVE’,
  10 time_limit => 60,
  11 task_name => ‘my_sql_tuning_task_2’,
  12 description =>’TASK to tune a query on table t1′);
  13 END;
  14  /
 
 PL/SQL procedure successfully completed.

然后执行上述自动调整任务

SQL> begin
  2  dbms_sqltune.execute_tuning_task(task_name => ‘my_sql_tuning_task_2’);
  3  end;
  4  /

 PL/SQL procedure successfully completed.

然后我们就可以使用 DBMS_SQLTUNE.REPORT_TUNING_TASK 来查看上述自动调整任务的调整结果:
SQL> set long 9000
 SQL> set longchunksize 1000
 SQL> set linesize 800
 SQL> select dbms_sqltune.report_tuning_task(‘my_sql_tuning_task_2’) from dual;

 DBMS_SQLTUNE.REPORT_TUNING_TASK(‘MY_SQL_TUNING_TASK_2’)
 ————————————————————————————————-
 Tuning Task Name  : my_sql_tuning_task_2
 Tuning Task Owner  : SYS
 Workload Type  : Single SQL Statement
 Scope  : COMPREHENSIVE
 Time Limit(seconds): 60
 Completion Status  : COMPLETED
 Started at  : 04/13/2016 23:08:28
 Completed at  : 04/13/2016 23:08:28

 DBMS_SQLTUNE.REPORT_TUNING_TASK(‘MY_SQL_TUNING_TASK_2’)
 —————————————————————————————————
 Schema Name: SYS
 SQL ID  : 4bh6sn1zvpgq7
 SQL Text  : select /*+ no_index(t1 idx_t1) */ * from t1 where n=1

 ——————————————————————————-
 FINDINGS SECTION (1 finding)
 ——————————————————————————-

 1- SQL Profile Finding (see explain plans section below)
 ——————————————————–

 DBMS_SQLTUNE.REPORT_TUNING_TASK(‘MY_SQL_TUNING_TASK_2’)
 —————————————————————————–

  Recommendation (estimated benefit: 90.91%)
  ——————————————
  – Consider accepting the recommended SQL profile.
    execute dbms_sqltune.accept_sql_profile(task_name =>
    ‘my_sql_tuning_task_2’, task_owner => ‘SYS’, replace => TRUE);

  Validation results
  ——————
  The SQL profile was tested by executing both its plan and the original plan

 DBMS_SQLTUNE.REPORT_TUNING_TASK(‘MY_SQL_TUNING_TASK_2’)

 DBMS_SQLTUNE.REPORT_TUNING_TASK(‘MY_SQL_TUNING_TASK_2’)
 ————————————————————————————————
  Physical Read Bytes:      0 0
  Physical Write Bytes:      0 0
  Rows Processed:      1 1
  Fetches:      1 1
  Executions:      1 1

  Notes
  —–
  1. Statistics for the original plan were averaged over 10 executions.
  2. Statistics for the SQL profile plan were averaged over 10 executions.

 DBMS_SQLTUNE.REPORT_TUNING_TASK(‘MY_SQL_TUNING_TASK_2’)
 ————————————————————————————-

 ——————————————————————————-
 EXPLAIN PLANS SECTION
 ——————————————————————————-

 1- Original With Adjusted Cost
 ——————————
 Plan hash value: 3617692013

 ————————————————————————–
 | Id  | Operation  | Name | Rows  | Bytes | Cost (%CPU)| Time |

 DBMS_SQLTUNE.REPORT_TUNING_TASK(‘MY_SQL_TUNING_TASK_2’)
 ———————————————————————————————
 |  0 | SELECT STATEMENT  | |    1 |    4 |    7  (0)| 00:00:01 |
 |*  1 |  TABLE ACCESS FULL| T1 |    1 |    4 |    7  (0)| 00:00:01 |
 ————————————————————————–

 Predicate Information (identified by operation id):
 —————————————————

    1 – filter(“N”=1)

 2- Using SQL Profile

 DBMS_SQLTUNE.REPORT_TUNING_TASK(‘MY_SQL_TUNING_TASK_2’)
 ————————————————————————————————-
 Plan hash value: 1369807930

 —————————————————————————
 | Id  | Operation | Name  | Rows  | Bytes | Cost (%CPU)| Time  |
 —————————————————————————
 |  0 | SELECT STATEMENT |  | 1 | 4 | 1  (0)| 00:00:01 |
 |*  1 |  INDEX RANGE SCAN| IDX_T1 | 1 | 4 | 1  (0)| 00:00:01 |
 —————————————————————————

 Predicate Information (identified by operation id):

 DBMS_SQLTUNE.REPORT_TUNING_TASK(‘MY_SQL_TUNING_TASK_2’)
 ————————————————————————————————

    1 – access(“N”=1)

 ——————————————————————————-

从上面的调整结果,我们可以看到,他已经为我们目标 SQL 找到了更好的执行计划,并且也完成了针对该 SQL 的 Automatic 类型的 SQL Profile,如果我们使用    execute dbms_sqltune.accept_sql_profile(task_name =>  ‘my_sql_tuning_task_2’, task_owner => ‘SYS’, replace => TRUE);
相应时间将会有 89.9% 的改善,逻辑读将会有 90.9 % 的改善,并且接受后将会有全表扫描改变为 IDX_T1 的索引范围扫描。

 然后我们按照 oracle 提示接受这个 SQL profile,并重新查看执行计划
SQL>  execute dbms_sqltune.accept_sql_profile(task_name =>  ‘my_sql_tuning_task_2’, task_owner => ‘SYS’, replace => TRUE);

 PL/SQL procedure successfully completed.

 

SQL> select /*+ no_index(t1 idx_t1) */ * from t1 where n=1;

 N
 ———-
 1

 SQL>  select * from table(dbms_xplan.display_cursor(null,null,’advanced’));

 PLAN_TABLE_OUTPUT
 —————————————————————————————————
 SQL_ID 1kg76709mx29d, child number 0
 ————————————-
 select /*+ no_index(t1 idx_t1) */ * from t1 where n=1

 Plan hash value: 1369807930

 —————————————————————————
 | Id  | Operation | Name  | Rows  | Bytes | Cost (%CPU)| Time  |
 —————————————————————————
 |  0 | SELECT STATEMENT |  |  |  | 1 (100)|  |
 |*  1 |  INDEX RANGE SCAN| IDX_T1 | 1 | 4 | 1  (0)| 00:00:01 |

 PLAN_TABLE_OUTPUT
 —————————————————————————

 Query Block Name / Object Alias (identified by operation id):
 ————————————————————-

    1 – SEL$1 / T1@SEL$1

 Outline Data
 ————-

  /*+

 PLAN_TABLE_OUTPUT
 ———————————————————————————————————–
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE(‘11.2.0.4’)
      DB_VERSION(‘11.2.0.4’)
      ALL_ROWS
      OUTLINE_LEAF(@”SEL$1″)
      INDEX(@”SEL$1″ “T1″@”SEL$1” (“T1″.”N”))
      END_OUTLINE_DATA
  */

 Predicate Information (identified by operation id):

 PLAN_TABLE_OUTPUT
 ————————————————

    1 – access(“N”=1)

 Column Projection Information (identified by operation id):
 ———————————————————–

    1 – “N”[NUMBER,22]

 Note
 —–

 PLAN_TABLE_OUTPUT
 ————————————————-
    – SQL profile SYS_SQLPROF_0154103a51870000 used for this statement

 46 rows selected.

 

我们可以看到 Note 部分 SQL profile SYS_SQLPROF_0154103a51870000 used for this statement,这说明我们刚才接受的 SQL Profile 已经生效了,这同时也说明 Automatic 类型的 SQL Profile 确实可以再不改变目标 SQL 的 SQl 文本的情况下更改其执行计划

 接下来我们尝试将 where 的条件从 n = 1 改变为 n =2, 并查看执行计划 SQL>  select /*+ no_index(t1 idx_t1) */ * from t1 where n=2;

 N
 ———-
 2

 SQL>  select * from table(dbms_xplan.display_cursor(null,null,’advanced’));

 PLAN_TABLE_OUTPUT
 ——————————————————————————–
 SQL_ID 36wrvgrswajnh, child number 0
 ————————————-
  select /*+ no_index(t1 idx_t1) */ * from t1 where n=2

 Plan hash value: 3617692013

 ————————————————————————–
 | Id  | Operation  | Name | Rows  | Bytes | Cost (%CPU)| Time |
 ————————————————————————–
 |  0 | SELECT STATEMENT  | | | |    7 (100)| |
 |*  1 |  TABLE ACCESS FULL| T1 |    1 |    4 |    7  (0)| 00:00:01 |

 PLAN_TABLE_OUTPUT
 ——————————————————————————–

 Query Block Name / Object Alias (identified by operation id):
 ————————————————————-

    1 – SEL$1 / T1@SEL$1

 Outline Data
 ————-

  /*+

 PLAN_TABLE_OUTPUT
 ——————————————————————————–
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE(‘11.2.0.4’)
      DB_VERSION(‘11.2.0.4’)
      ALL_ROWS
      OUTLINE_LEAF(@”SEL$1″)
      FULL(@”SEL$1″ “T1″@”SEL$1”)
      END_OUTLINE_DATA
  */

 Predicate Information (identified by operation id):

 PLAN_TABLE_OUTPUT
 ——————————————————————————–

    1 – filter(“N”=2)

 Column Projection Information (identified by operation id):
 ———————————————————–

    1 – “N”[NUMBER,22]

 42 rows selected.

我们发现还是走了全表扫描,要想使上面的 SQL_PROFILE 生效,我们需要加上 FORCE_MATCH=TRUE,true 的含义,就是 where 条件中值发生变化,但是 SQL_Profile 仍然有效

SQL> execute dbms_sqltune.accept_sql_profile(task_name =>  ‘my_sql_tuning_task_2’, task_owner => ‘SYS’, replace => TRUE,force_match => true);

 PL/SQL procedure successfully completed.

再次查看相对应的执行计划

SQL> select /*+ no_index(t1 idx_t1) */ * from t1 where n=2;

 N
 ———-
 2

 SQL> select * from table(dbms_xplan.display_cursor(null,null,’advanced’));

 PLAN_TABLE_OUTPUT
 ——————————————————————————–
 SQL_ID c4j6hxkqudj1s, child number 0
 ————————————-
 select /*+ no_index(t1 idx_t1) */ * from t1 where n=2

 Plan hash value: 1369807930

 —————————————————————————
 | Id  | Operation | Name  | Rows  | Bytes | Cost (%CPU)| Time  |
 —————————————————————————
 |  0 | SELECT STATEMENT |  |  |  | 1 (100)|  |
 |*  1 |  INDEX RANGE SCAN| IDX_T1 | 1 | 4 | 1  (0)| 00:00:01 |

 PLAN_TABLE_OUTPUT
 ——————————————————————————–

 Query Block Name / Object Alias (identified by operation id):
 ————————————————————-

    1 – SEL$1 / T1@SEL$1

 Outline Data
 ————-

  /*+

 PLAN_TABLE_OUTPUT
 ——————————————————————————–
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE(‘11.2.0.4’)
      DB_VERSION(‘11.2.0.4’)
      ALL_ROWS
      OUTLINE_LEAF(@”SEL$1″)
      INDEX(@”SEL$1″ “T1″@”SEL$1” (“T1″.”N”))
      END_OUTLINE_DATA
  */

 Predicate Information (identified by operation id):

 PLAN_TABLE_OUTPUT
 ——————————————————————————–

    1 – access(“N”=2)

 Column Projection Information (identified by operation id):
 ———————————————————–

    1 – “N”[NUMBER,22]

 Note
 —–

 PLAN_TABLE_OUTPUT
 ———————————————
    – SQL profile SYS_SQLPROF_015410470fa40001 used for this statement

 46 rows selected.

 

这是我们可以发现这次的执行计划走的是索引,为了再次验证新生成的 SQL_Profile 对其他值也有效,我们再次尝试 n =3

 SQL> select /*+ no_index(t1 idx_t1) */ * from t1 where n=3;

 N
 ———-
 3

 SQL> select * from table(dbms_xplan.display_cursor(null,null,’advanced’));

 PLAN_TABLE_OUTPUT
 ——————————————————————————–
 SQL_ID 0zz8t0qnm15hj, child number 0
 ————————————-
 select /*+ no_index(t1 idx_t1) */ * from t1 where n=3

 Plan hash value: 1369807930

 —————————————————————————
 | Id  | Operation | Name  | Rows  | Bytes | Cost (%CPU)| Time  |
 —————————————————————————
 |  0 | SELECT STATEMENT |  |  |  | 1 (100)|  |
 |*  1 |  INDEX RANGE SCAN| IDX_T1 | 1 | 4 | 1  (0)| 00:00:01 |

 PLAN_TABLE_OUTPUT
 ——————————————————————————–
 —————————————————————————

 Query Block Name / Object Alias (identified by operation id):
 ————————————————————-

    1 – SEL$1 / T1@SEL$1

 Outline Data
 ————-

  /*+

 PLAN_TABLE_OUTPUT
 ——————————————————————————–
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE(‘11.2.0.4’)
      DB_VERSION(‘11.2.0.4’)
      ALL_ROWS
      OUTLINE_LEAF(@”SEL$1″)
      INDEX(@”SEL$1″ “T1″@”SEL$1” (“T1″.”N”))
      END_OUTLINE_DATA
  */

 Predicate Information (identified by operation id):

 PLAN_TABLE_OUTPUT
 ——————————————————————————–
 —————————————————

    1 – access(“N”=3)

 Column Projection Information (identified by operation id):
 ———————————————————–

    1 – “N”[NUMBER,22]

 Note
 —–

 PLAN_TABLE_OUTPUT
 ——————————————————————————–
    – SQL profile SYS_SQLPROF_015410470fa40001 used for this statement

 46 rows selected.

结论是仍旧有效。

–End.

本文永久更新链接地址 :http://www.linuxidc.com/Linux/2016-04/130334.htm

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-22发表,共计14915字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19348
评论数
4
阅读量
7798968
文章搜索
热门文章
开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南 大家好,我是星哥。之前介绍了腾讯云的 Code...
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
云服务器部署服务器面板1Panel:小白轻松构建Web服务与面板加固指南

云服务器部署服务器面板1Panel:小白轻松构建Web服务与面板加固指南

云服务器部署服务器面板 1Panel:小白轻松构建 Web 服务与面板加固指南 哈喽,我是星哥,经常有人问我不...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
【开源神器】微信公众号内容单篇、批量下载软件

【开源神器】微信公众号内容单篇、批量下载软件

【开源神器】微信公众号内容单篇、批量下载软件 大家好,我是星哥,很多人都希望能高效地保存微信公众号的文章,用于...
自己手撸一个AI智能体—跟创业大佬对话

自己手撸一个AI智能体—跟创业大佬对话

自己手撸一个 AI 智能体 — 跟创业大佬对话 前言 智能体(Agent)已经成为创业者和技术人绕...
开发者福利:免费 .frii.site 子域名,一分钟申请即用

开发者福利:免费 .frii.site 子域名,一分钟申请即用

  开发者福利:免费 .frii.site 子域名,一分钟申请即用 前言 在学习 Web 开发、部署...
【1024程序员】我劝你赶紧去免费领一个AWS、华为云等的主机

【1024程序员】我劝你赶紧去免费领一个AWS、华为云等的主机

【1024 程序员】我劝你赶紧去免费领一个 AWS、华为云等的主机 每年 10 月 24 日,程序员们都会迎来...
开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南 大家好,我是星哥。之前介绍了腾讯云的 Code...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
零成本上线!用 Hugging Face免费服务器+Docker 快速部署HertzBeat 监控平台

零成本上线!用 Hugging Face免费服务器+Docker 快速部署HertzBeat 监控平台

零成本上线!用 Hugging Face 免费服务器 +Docker 快速部署 HertzBeat 监控平台 ...
12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换...
星哥带你玩飞牛 NAS-9:全能网盘搜索工具 13 种云盘一键搞定!

星哥带你玩飞牛 NAS-9:全能网盘搜索工具 13 种云盘一键搞定!

星哥带你玩飞牛 NAS-9:全能网盘搜索工具 13 种云盘一键搞定! 前言 作为 NAS 玩家,你是否总被这些...
自己手撸一个AI智能体—跟创业大佬对话

自己手撸一个AI智能体—跟创业大佬对话

自己手撸一个 AI 智能体 — 跟创业大佬对话 前言 智能体(Agent)已经成为创业者和技术人绕...
安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装 Black 群晖 DSM7.2 系统安装教程(在 Vmware 虚拟机中、实体机均可)! 前言 大家好,...