Rumah >pangkalan data >tutorial mysql >sql profile简介

sql profile简介

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBasal
2016-06-07 16:40:351617semak imbas

关于绑定sql的执行计划个人一直用的是oracle的sql plan baseline,其实oracle 10g就推出了sql profile来绑定执行计划,下面来简单的了解下oracle的sql profile的功能。 sql profile大体是实现两个功能: 1绑定现有sql的执行计划 2 在不修改代码的情况下使目

关于绑定sql的执行计划个人一直用的是oracle的sql plan baseline,其实oracle 10g就推出了sql profile来绑定执行计划,下面来简单的了解下oracle的sql profile的功能。

sql profile大体是实现两个功能:
1绑定现有sql的执行计划
2 在不修改代码的情况下使目标sql语句按照执行的执行计划执行,这两个功能sql plan baseline也是可以实现的,而比sql profile更加优秀的就是sql plan baseline还能够在sql运行是生成更优秀的执行计划基线,我们可以演练这个新的sql plan baseline来决定是否采用这个sql plan baseline。

sql profile有两种类型:一种是automatic类型,另一种是manual类型

automatic类型的sql profile是针对目标sql获取到一些额外的调整信息(类似oracle的动态采样来采集额外的信息),这些信息存储在数据字典中,当有了automatic类型的sql profile后,优化器产生执行计划时会根据目标sql所涉及统计信息等内容做相应的调整来保证选择最优的执行计划。

需要注意的automatic的sql profile并不是像stored outlines、sql plan baseline那样锁定目标sql的执行计划,automatic的sql profile在原则上只是提供了一些额外的统计信息,这些额外的统计信息必须于原目标sql的涉及的相关统计内容一起作用才能得到新的执行计划,如果原sql的统计信息等内容发生重大变化,即使原有的automatic类型的sql profile没有改变,该sql的执行计划也可能会发生变化,接下来xiaoyu会贴出部分case以供大家参考。

SQL>create table t_auto01 as select * from dba_objects;
SQL>create index ind_objectid on t_auto01(object_id);
SQL> select max(object_id) from t_auto01;

MAX(OBJECT_ID)
--------------
         87823
SQL>update  t_auto01 set object_id=100000  where object_id SQL>commit;
SQL>exec dbms_stats.gather_table_stats(ownname=>USER,tabname=>'T_AUTO01',cascade=>true);

SQL>set autotrace traceonly;
SQL> select /*+index(t_auto01 ind_objectid)*/* from t_auto01 where object_id=100000;

86366 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 4224651809

--------------------------------------------------------------------------------------------
| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |              | 86348 |  8095K|  1388   (1)| 00:00:17 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T_AUTO01     | 86348 |  8095K|  1388   (1)| 00:00:17 |
|*  2 |   INDEX RANGE SCAN          | IND_OBJECTID | 86348 |       |   153   (0)| 00:00:02 |
--------------------------------------------------------------------------------------------

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

   2 - access("OBJECT_ID"=100000)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      12806  consistent gets
          0  physical reads
          0  redo size
    9767726  bytes sent via SQL*Net to client
      63850  bytes received via SQL*Net from client
       5759  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      86366  rows processed

用STA生成automatic sql profile

SQL> select sql_id from v$sql where sql_text like 'select /*+index(t_auto01 ind_objectid)*/* from t_auto01 where object_id=100000%';

SQL_ID
-------------
5tvdfn4y8z5gg

declare
my_task_name varchar2(30);
begin
my_task_name:=dbms_sqltune.create_tuning_task(
sql_id=>'601ccgpfh9jcv',
scope=>'COMPREHENSIVE',
task_name=>'my_tuning_task'
);
dbms_sqltune.execute_tuning_task(task_name=>'my_tuning_task');
end;
/

SQL> set long 100000
SQL> select dbms_sqltune.report_tuning_task(task_name=>'my_tuning_task') from dual;

DBMS_SQLTUNE.REPORT_TUNING_TASK(TASK_NAME=>'MY_TUNING_TASK')
--------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
-------------------------------------------------------------------------------
Tuning Task Name   : my_tuning_task
Tuning Task Owner  : SYS
Workload Type      : Single SQL Statement
Scope              : COMPREHENSIVE
Time Limit(seconds): 1800
Completion Status  : COMPLETED
Started at         : 12/09/2014 19:01:37
Completed at       : 12/09/2014 19:01:37

-------------------------------------------------------------------------------
Schema Name: SYS
SQL ID     : 5tvdfn4y8z5gg
SQL Text   : select /*+index(t_auto01 ind_objectid)*/* from t_auto01 where
             object_id=100000

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

1- SQL Profile Finding (see explain plans section below)
--------------------------------------------------------
  A potentially better execution plan was found for this statement.

  Recommendation (estimated benefit: 10.83%)
  ------------------------------------------
  - Consider accepting the recommended SQL profile.
    execute dbms_sqltune.accept_sql_profile(task_name => 'my_tuning_task',
            task_owner => 'SYS', replace => TRUE);

  Validation results
  ------------------
  The SQL profile was tested by executing both its plan and the original plan
  and measuring their respective execution statistics. A plan may have been
  only partially executed if the other could be run to completion in less time.

                           Original Plan  With SQL Profile  % Improved
                           -------------  ----------------  ----------
  Completion Status:            COMPLETE          COMPLETE
  Elapsed Time (s):             .018247           .007709      57.75 %
  CPU Time (s):                 .002199           .000699      68.21 %
  User I/O Time (s):                  0                 0
  Buffer Gets:                     1386              1236      10.82 %
  Physical Read Requests:             0                 0
  Physical Write Requests:            0                 0
  Physical Read Bytes:                0                 0
  Physical Write Bytes:               0                 0
  Rows Processed:                 86366             86366
  Fetches:                        86366             86366
  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.

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

1- Original With Adjusted Cost
------------------------------
Plan hash value: 4224651809

--------------------------------------------------------------------------------
------------
| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)
| Time     |
--------------------------------------------------------------------------------
------------
|   0 | SELECT STATEMENT            |              | 86348 |  8095K|  1388   (1)
| 00:00:17 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T_AUTO01     | 86348 |  8095K|  1388   (1)
| 00:00:17 |
|*  2 |   INDEX RANGE SCAN          | IND_OBJECTID | 86348 |       |   153   (0)
| 00:00:02 |
--------------------------------------------------------------------------------
------------

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

   2 - access("OBJECT_ID"=100000)

2- Using SQL Profile
--------------------
Plan hash value: 795571617

------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          | 86348 |  8095K|   336   (1)| 00:00:05 |
|*  1 |  TABLE ACCESS FULL| T_AUTO01 | 86348 |  8095K|   336   (1)| 00:00:05 |
------------------------------------------------------------------------------

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

   1 - filter("OBJECT_ID"=100000)

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

antomatic sql profile已经生效:

SQL>execute dbms_sqltune.accept_sql_profile(task_name => 'my_tuning_task’, task_owner => 'SYS', replace => TRUE);
SQL> select /*+index(t_auto01 ind_objectid)*/* from t_auto01 where object_id=100000;

86366 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 795571617

------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          | 86348 |  8095K|   336   (1)| 00:00:05 |
|*  1 |  TABLE ACCESS FULL| T_AUTO01 | 86348 |  8095K|   336   (1)| 00:00:05 |
------------------------------------------------------------------------------

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

   1 - filter("OBJECT_ID"=100000)

Note
-----
   - SQL profile "SYS_SQLPROF_014a3230758f0000" used for this statement

即使此时sql text有出现大小写、空格类、换行等的变化,sql profile依然可以生效

SQL> select /*+index(t_auto01 ind_objectid)*/* from T_AUTO01  where object_id=100000;

86366 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 795571617

------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          | 86348 |  8095K|   336   (1)| 00:00:05 |
|*  1 |  TABLE ACCESS FULL| T_AUTO01 | 86348 |  8095K|   336   (1)| 00:00:05 |
------------------------------------------------------------------------------

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

   1 - filter("OBJECT_ID"=100000)

Note
-----
   - SQL profile "SYS_SQLPROF_014a3230758f0000" used for this statement

即使表发生了ddl,只要不影响原来的sql执行,相应的sql profile依然生效。

SQL> alter table t_auto01 add edate date;

Table altered.

SQL> select /*+index(t_auto01 ind_objectid)*/* from T_AUTO01  where object_id=100000;

86366 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 795571617

------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          | 86348 |  8095K|   336   (1)| 00:00:05 |
|*  1 |  TABLE ACCESS FULL| T_AUTO01 | 86348 |  8095K|   336   (1)| 00:00:05 |
------------------------------------------------------------------------------

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

   1 - filter("OBJECT_ID"=100000)

Note
-----
   - SQL profile "SYS_SQLPROF_014a3230758f0000" used for this statement

如果我们具体谓词条件对应的具体值出现了变化,此时sql profile是没有办法生效的。

SQL> select /*+index(t_auto01 ind_objectid)*/* from t_auto01 where object_id=1000001;

no rows selected

Execution Plan
----------------------------------------------------------
Plan hash value: 4224651809

--------------------------------------------------------------------------------------------
| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |              |     1 |    96 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T_AUTO01     |     1 |    96 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IND_OBJECTID |     1 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

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

   2 - access("OBJECT_ID"=1000001)

当然如果sql text出现了类似下列的变更,同样sql profile也无法生效。

SQL> select /*+index(t_auto01 ind_objectid)*/* from t_auto01 a where object_id=100000;

86366 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 795571617

------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          | 86348 |  8095K|   336   (1)| 00:00:05 |
|*  1 |  TABLE ACCESS FULL| T_AUTO01 | 86348 |  8095K|   336   (1)| 00:00:05 |
------------------------------------------------------------------------------

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

   1 - filter("OBJECT_ID"=100000)

那么接下来还有一个问题,就是如果我们的应用程序没有写bind value,但是我们要绑定一系列的值都走同一类的profile,其实这个也比较容易,oracle提供的dbms_sqltune.accept_sql_profile中有个参数是force_match参数,该参数默认是false,当修改为true后,谓词的具体值即使发生了变化,sql profile依然生效。

SQL> execute dbms_sqltune.accept_sql_profile(task_name => 'my_tuning_task',task_owner => 'SYS', replace => TRUE,force_match=>true);

PL/SQL procedure successfully completed.

SQL> select /*+index(t_auto01 ind_objectid)*/* from T_AUTO01  where object_id=100001;

no rows selected

Execution Plan
----------------------------------------------------------
Plan hash value: 4224651809

--------------------------------------------------------------------------------------------
| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |              |     8 |   776 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T_AUTO01     |     8 |   776 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IND_OBJECTID |     8 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

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

   2 - access("OBJECT_ID"=100001)

Note
-----
   - SQL profile "SYS_SQLPROF_014a323f8ddc0001" used for this statement


Statistics
----------------------------------------------------------
          7  recursive calls
          0  db block gets
          7  consistent gets
          1  physical reads
          0  redo size
       1410  bytes sent via SQL*Net to client
        512  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed

我们发现此时加上了force_matching=>true参数后,谓词具体对应值变化的sql走了一个新的sql profile SYS_SQLPROF_014a323f8ddc0001,而且这个sql profile并不走SYS_SQLPROF_014a3230758f0000的全表扫描的执行计划,而是走更加高效的index range scan,这里需要明确加上force_match=>true新生成的sql profile不一定跟之前的sql profile执行计划一样,因为automatic sql profile仅仅只是一些额外的统计信息来保证生成更准确高效的执行计划。

同样还需要注意的即使是同一个sql profile也可能会产生不同的执行计划:

SQL> exec dbms_sqltune.drop_sql_profile(‘SYS_SQLPROF_014a323f8ddc0001’);
SQL> exec dbms_sqltune.drop_sql_profile(‘SYS_SQLPROF_014a3230758f0000’);
SQL> exec dbms_sqltune.drop_tuning_task(task_name=>'my_tuning_task');

重新生成一个sql profile
SQL> declare
  2  my_task_name varchar2(30);
  3  begin
  4  my_task_name:=dbms_sqltune.create_tuning_task(
  5  sql_id=>'601ccgpfh9jcv',
  6  scope=>'COMPREHENSIVE',
  7  task_name=>'my_tuning_task'
  8  );
  9  dbms_sqltune.execute_tuning_task(task_name=>'my_tuning_task');
 10  end;
 11  /

PL/SQL procedure successfully completed.

SQL> set long 199999
SQL> select dbms_sqltune.report_tuning_task(task_name=>'my_tuning_task') from dual;

DBMS_SQLTUNE.REPORT_TUNING_TASK(TASK_NAME=>'MY_TUNING_TASK')
--------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
-------------------------------------------------------------------------------
Tuning Task Name   : my_tuning_task
Tuning Task Owner  : SYS
Workload Type      : Single SQL Statement
Scope              : COMPREHENSIVE
Time Limit(seconds): 1800
Completion Status  : COMPLETED
Started at         : 12/09/2014 19:57:36
Completed at       : 12/09/2014 19:57:36

-------------------------------------------------------------------------------
Schema Name: SYS
SQL ID     : 601ccgpfh9jcv
SQL Text   : select /*+index(t_auto01 ind_objectid)*/* from T_AUTO01  where
             object_id=100000

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

1- SQL Profile Finding (see explain plans section below)
--------------------------------------------------------
  A potentially better execution plan was found for this statement.

  Recommendation (estimated benefit: 10.82%)
  ------------------------------------------
  - Consider accepting the recommended SQL profile.
    execute dbms_sqltune.accept_sql_profile(task_name => 'my_tuning_task',
            task_owner => 'SYS', replace => TRUE);

  Validation results
  ------------------
  The SQL profile was tested by executing both its plan and the original plan
  and measuring their respective execution statistics. A plan may have been
  only partially executed if the other could be run to completion in less time.

                           Original Plan  With SQL Profile  % Improved
                           -------------  ----------------  ----------
  Completion Status:            COMPLETE          COMPLETE
  Elapsed Time (s):             .021363            .00914      57.21 %
  CPU Time (s):                 .021396           .009198      57.01 %
  User I/O Time (s):                  0                 0
  Buffer Gets:                     1385              1236      10.75 %
  Physical Read Requests:             0                 0
  Physical Write Requests:            0                 0
  Physical Read Bytes:                0                 0
  Physical Write Bytes:               0                 0
  Rows Processed:                 86371             86371
  Fetches:                        86371             86371
  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.

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

1- Original With Adjusted Cost
------------------------------
Plan hash value: 4224651809

--------------------------------------------------------------------------------
------------
| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)
| Time     |
--------------------------------------------------------------------------------
------------
|   0 | SELECT STATEMENT            |              | 86363 |  8096K|  1386   (1)
| 00:00:17 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T_AUTO01     | 86363 |  8096K|  1386   (1)
| 00:00:17 |
|*  2 |   INDEX RANGE SCAN          | IND_OBJECTID | 86363 |       |   152   (0)
| 00:00:02 |
--------------------------------------------------------------------------------
------------

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

   2 - access("OBJECT_ID"=100000)

2- Using SQL Profile
--------------------
Plan hash value: 795571617

------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          | 86363 |  8096K|   336   (1)| 00:00:05 |
|*  1 |  TABLE ACCESS FULL| T_AUTO01 | 86363 |  8096K|   336   (1)| 00:00:05 |
------------------------------------------------------------------------------

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

   1 - filter("OBJECT_ID"=100000)

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

force_match方式accept sql profile:

SQL>  execute dbms_sqltune.accept_sql_profile(task_name => 'my_tuning_task',task_owner => 'SYS', replace => TRUE,force_match=>true);

PL/SQL procedure successfully completed.

SQL> select /*+index(t_auto01 ind_objectid)*/* from T_AUTO01  where object_id=100000;

86371 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 795571617

------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          | 86363 |  8096K|   336   (1)| 00:00:05 |
|*  1 |  TABLE ACCESS FULL| T_AUTO01 | 86363 |  8096K|   336   (1)| 00:00:05 |
------------------------------------------------------------------------------

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

   1 - filter("OBJECT_ID"=100000)

Note
-----
   - SQL profile "SYS_SQLPROF_014a325968080002" used for this statement


Statistics
----------------------------------------------------------
          7  recursive calls
          0  db block gets
       6913  consistent gets
          1  physical reads
          0  redo size
    4045316  bytes sent via SQL*Net to client
      63861  bytes received via SQL*Net from client
       5760  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      86371  rows processed

SQL> select /*+index(t_auto01 ind_objectid)*/* from T_AUTO01  where object_id=1;

no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 4224651809

--------------------------------------------------------------------------------------------
| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |              |     1 |    96 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T_AUTO01     |     1 |    96 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IND_OBJECTID |     1 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

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

   2 - access("OBJECT_ID"=1)

Note
-----
   - SQL profile "SYS_SQLPROF_014a325968080002" used for this statement


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        300  consistent gets
          0  physical reads
          0  redo size
       1343  bytes sent via SQL*Net to client
        512  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed

更新t_auto01表的数据全部为object_id=1,造成数据倾斜

SQL> update t_auto01 set object_id=1;
86371 rows updated.
SQL> commit;
Commit complete.

这里的sql profile对应的执行计划依然是index range scan

SQL> select /*+index(t_auto01 ind_objectid)*/* from T_AUTO01  where object_id=1;

86371 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 4224651809

--------------------------------------------------------------------------------------------
| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |              |     1 |    96 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T_AUTO01     |     1 |    96 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IND_OBJECTID |     1 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

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

   2 - access("OBJECT_ID"=1)

Note
-----
   - SQL profile "SYS_SQLPROF_014a325968080002" used for this statement

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      12957  consistent gets
          0  physical reads
          0  redo size
    9768433  bytes sent via SQL*Net to client
      63861  bytes received via SQL*Net from client
       5760  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      86371  rows processed

重新收集下统计信息:

SQL> exec dbms_stats.gather_table_stats(ownname=>USER,tabname=>'T_AUTO01',cascade=>true);

PL/SQL procedure successfully completed.

SQL> select /*+index(t_auto01 ind_objectid)*/* from T_AUTO01  where object_id=1;

86371 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 795571617

------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          | 86363 |  8096K|   336   (1)| 00:00:05 |
|*  1 |  TABLE ACCESS FULL| T_AUTO01 | 86363 |  8096K|   336   (1)| 00:00:05 |
------------------------------------------------------------------------------

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

   1 - filter("OBJECT_ID"=1)

Note
-----
   - SQL profile "SYS_SQLPROF_014a325968080002" used for this statement


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      12957  consistent gets
          0  physical reads
          0  redo size
    9768433  bytes sent via SQL*Net to client
      63861  bytes received via SQL*Net from client
       5760  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      86371  rows processed

sql profle对应的执行计划变成了full table scan。

这里我们需要明确的是如果重新收集了统计信息,automatic的sql profile的执行计划是有可能会发生变化的。

由于automatic sql profile只是一些额外的统计信息,这个将导致如果sql涉及的表统计信息发生变化,automatic的sql profile将无法绑定目标sql的执行计划。

下面来介绍下manual类型的sql profile,manual sql profile实际上就是一堆hint的组合,它能很好的绑定目标sql的执行计划,这个跟automatic sql profile是不相同的。

manual类型的sql profile同样可以在不改变目标sql的sql文本情况下调整其执行计划,

SQL> create table t_manual01 as select * from dba_objects;

Table created.

SQL> create index ind_manual_objid on t_manual01(object_id);

Index created.

SQL> exec dbms_stats.gather_table_stats(ownname=>USER,tabname=>'T_MANUAL01',cascade=>true);

PL/SQL procedure successfully completed.

SQL> select /*+index(t_manual01 ind_manual_objid)*/* from t_manual01 where object_id=1;

Execution Plan
----------------------------------------------------------
Plan hash value: 371934742

------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                  |     1 |    98 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T_MANUAL01       |     1 |    98 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IND_MANUAL_OBJID |     1 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------

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

   2 - access("OBJECT_ID"=1)

SQL> update t_manual01 set object_id=1;

86320 rows updated.
SQL> commit;

Commit complete.

此时由于全部object_id为1,全表扫描将更加适合

SQL> select /*+index(t_manual01 ind_manual_objid)*/* from t_manual01 where object_id=1;

Execution Plan
----------------------------------------------------------
Plan hash value: 371934742

------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                  |     1 |    98 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T_MANUAL01       |     1 |    98 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IND_MANUAL_OBJID |     1 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------

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

   2 - access("OBJECT_ID"=1)

SQL> select /*+full(t_manual01)*/* from t_manual01 where object_id=1;

86320 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1705140427

--------------------------------------------------------------------------------
| Id  | Operation         | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |            |     1 |    98 |   344   (1)| 00:00:05 |
|*  1 |  TABLE ACCESS FULL| T_MANUAL01 |     1 |    98 |   344   (1)| 00:00:05 |
--------------------------------------------------------------------------------

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

   1 - filter("OBJECT_ID"=1)

SQL> select sql_id,plan_hash_value,sql_text from v$sql where sql_text like 'select /*+index(t_manual01 ind_manual_objid)*/* from t_manual01 where object_id=1%';

SQL_ID        PLAN_HASH_VALUE SQL_TEXT
------------- --------------- ------------------------------------------------------------
5usjcvmsxj6mb   371934742 select /*+index(t_manual01 ind_manual_objid)*/* from t_manual01 where object_id=1


SQL> select sql_id,plan_hash_value,sql_text from v$sql where sql_text like 'select /*+full(t_manual01)*/* from t_manual01 where object_id=1%';

SQL_ID        PLAN_HASH_VALUE SQL_TEXT
------------- --------------- ------------------------------------------------------------
fp5ng25383cvk      1705140427 select /*+full(t_manual01)*/* from t_manual01 where object_id=1

SQL> select * from table(dbms_xplan.display_cursor('5usjcvmsxj6mb',null,'advanced'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  5usjcvmsxj6mb, child number 0
-------------------------------------
select /*+index(t_manual01 ind_manual_objid)*/* from t_manual01 where
object_id=1

Plan hash value: 371934742

------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                  |       |       |     2 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID| T_MANUAL01       |     1 |    98 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IND_MANUAL_OBJID |     1 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------

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

   1 - SEL$1 / T_MANUAL01@SEL$1
   2 - SEL$1 / T_MANUAL01@SEL$1

Outline Data
-------------

  /*+
      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_RS_ASC(@"SEL$1" "T_MANUAL01"@"SEL$1" ("T_MANUAL01"."OBJECT_ID"))
      END_OUTLINE_DATA
  */

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

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  fp5ng25383cvk, child number 0
-------------------------------------
select /*+full(t_manual01)*/* from t_manual01 where object_id=1

Plan hash value: 1705140427

--------------------------------------------------------------------------------
| Id  | Operation         | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |            |       |       |   344 (100)|          |
|*  1 |  TABLE ACCESS FULL| T_MANUAL01 |     1 |    98 |   344   (1)| 00:00:05 |
--------------------------------------------------------------------------------

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

   1 - SEL$1 / T_MANUAL01@SEL$1

Outline Data
-------------

  /*+
      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" "T_MANUAL01"@"SEL$1")
      END_OUTLINE_DATA
  */

这种移花接木的基本思路为:
1 coe_xfr_sql_profile.sql脚本生成目标sql的manual sql profile脚本
2 针对目标sql添加hint,直到sql能走出你需要的执行计划,针对这个sql用coe_xfr_sql_profile.sql脚本生成manual sql profile脚本
3 用修改后的sql生成的manual sql profile脚本中的outline data部分替换掉目标sql对应的manual sql profile脚本
4 执行目标sql的manual sql profile脚本生成manual sql profile

SQL> @coe_xfr_sql_profile.sql

Parameter 1:
SQL_ID (required)

Enter value for 1: 5usjcvmsxj6mb


PLAN_HASH_VALUE AVG_ET_SECS
--------------- -----------
      371934742        .052

Parameter 2:
PLAN_HASH_VALUE (required)

Enter value for 2: 371934742

Values passed to coe_xfr_sql_profile:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SQL_ID         : "5usjcvmsxj6mb"
PLAN_HASH_VALUE: "371934742"

SQL>BEGIN
  2    IF :sql_text IS NULL THEN
  3      RAISE_APPLICATION_ERROR(-20100, 'SQL_TEXT for SQL_ID &&sql_id. was not found in memory (gv$sqltext_with_newlines) or AWR (dba_hist_sqltext).');
  4    END IF;
  5  END;
  6  /
SQL>SET TERM OFF;
SQL>BEGIN
  2    IF :other_xml IS NULL THEN
  3      RAISE_APPLICATION_ERROR(-20101, 'PLAN for SQL_ID &&sql_id. and PHV &&plan_hash_value. was not found in memory (gv$sql_plan) or AWR (dba_hist_sql_plan).');
  4    END IF;
  5  END;
  6  /
SQL>SET TERM OFF;

Execute coe_xfr_sql_profile_5usjcvmsxj6mb_371934742.sql
on TARGET system in order to create a custom SQL Profile
with plan 371934742 linked to adjusted sql_text.


COE_XFR_SQL_PROFILE completed.

SQL> @coe_xfr_sql_profile.sql

Parameter 1:
SQL_ID (required)

Enter value for 1: fp5ng25383cvk


PLAN_HASH_VALUE AVG_ET_SECS
--------------- -----------
     1705140427         .06

Parameter 2:
PLAN_HASH_VALUE (required)

Enter value for 2: 1705140427

Values passed to coe_xfr_sql_profile:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SQL_ID         : "fp5ng25383cvk"
PLAN_HASH_VALUE: "1705140427"

SQL>BEGIN
  2    IF :sql_text IS NULL THEN
  3      RAISE_APPLICATION_ERROR(-20100, 'SQL_TEXT for SQL_ID &&sql_id. was not found in memory (gv$sqltext_with_newlines) or AWR (dba_hist_sqltext).');
  4    END IF;
  5  END;
  6  /
SQL>SET TERM OFF;
SQL>BEGIN
  2    IF :other_xml IS NULL THEN
  3      RAISE_APPLICATION_ERROR(-20101, 'PLAN for SQL_ID &&sql_id. and PHV &&plan_hash_value. was not found in memory (gv$sql_plan) or AWR (dba_hist_sql_plan).');
  4    END IF;
  5  END;
  6  /
SQL>SET TERM OFF;

Execute coe_xfr_sql_profile_fp5ng25383cvk_1705140427.sql
on TARGET system in order to create a custom SQL Profile
with plan 1705140427 linked to adjusted sql_text.


COE_XFR_SQL_PROFILE completed.

生成两个sql_id脚本后

[oracle@redhat_ora11g ~]$ vi coe_xfr_sql_profile_5usjcvmsxj6mb_371934742.sql
。。。
DECLARE
sql_txt CLOB;
h       SYS.SQLPROF_ATTR;
BEGIN
sql_txt := q'[
select /*+index(t_manual01 ind_manual_objid)
*/* from t_manual01 where object_id=1
]';
h := SYS.SQLPROF_ATTR(
q'[BEGIN_OUTLINE_DATA]',
q'[IGNORE_OPTIM_EMBEDDED_HINTS]',
q'[OPTIMIZER_FEATURES_ENABLE('11.2.0.4')]',
q'[DB_VERSION('11.2.0.4')]',
q'[ALL_ROWS]',
q'[OUTLINE_LEAF(@"SEL$1")]',
q'[INDEX_RS_ASC(@"SEL$1" "T_MANUAL01"@"SEL$1" ("T_MANUAL01"."OBJECT_ID"))]',
q'[END_OUTLINE_DATA]');
:signature := DBMS_SQLTUNE.SQLTEXT_TO_SIGNATURE(sql_txt);
DBMS_SQLTUNE.IMPORT_SQL_PROFILE (
sql_text    => sql_txt,
profile     => h,
name        => 'coe_5usjcvmsxj6mb_371934742',
description => 'coe 5usjcvmsxj6mb 371934742 '||:signature||'',
category    => 'DEFAULT',
validate    => TRUE,
replace     => TRUE,
force_match => FALSE /* TRUE:FORCE (match even when different literals in SQL). FALSE:EXACT (similar to CURSOR_SHARING) */ );
END;
/
WHENEVER SQLERROR CONTINUE
SET ECHO OFF;
。。。

[oracle@redhat_ora11g ~]$ more coe_xfr_sql_profile_fp5ng25383cvk_1705140427.sql
。。。
DECLARE
sql_txt CLOB;
h       SYS.SQLPROF_ATTR;
BEGIN
sql_txt := q'[
select /*+full(t_manual01)
*/* from t_manual01 where object_id=1
]';
h := SYS.SQLPROF_ATTR(
q'[BEGIN_OUTLINE_DATA]',
q'[IGNORE_OPTIM_EMBEDDED_HINTS]',
q'[OPTIMIZER_FEATURES_ENABLE('11.2.0.4')]',
q'[DB_VERSION('11.2.0.4')]',
q'[ALL_ROWS]',
q'[OUTLINE_LEAF(@"SEL$1")]',
q'[FULL(@"SEL$1" "T_MANUAL01"@"SEL$1")]',
q'[END_OUTLINE_DATA]');
:signature := DBMS_SQLTUNE.SQLTEXT_TO_SIGNATURE(sql_txt);
DBMS_SQLTUNE.IMPORT_SQL_PROFILE (
sql_text    => sql_txt,
profile     => h,
name        => 'coe_fp5ng25383cvk_1705140427',
description => 'coe fp5ng25383cvk 1705140427 '||:signature||'',
category    => 'DEFAULT',
validate    => TRUE,
replace     => TRUE,
force_match => FALSE /* TRUE:FORCE (match even when different literals in SQL). FALSE:EXACT (similar to CURSOR_SHARING) */ );
END;
/
WHENEVER SQLERROR CONTINUE
SET ECHO OFF;
。。。

force_match => FALSE根据实际情况修改,默认为false,如果修改为true,谓词的具体值发生变化,sql profile依然生效。

将目标sql也就是coe_xfr_sql_profile_5usjcvmsxj6mb_371934742.sql脚本中的如下部分
h := SYS.SQLPROF_ATTR(
q'[BEGIN_OUTLINE_DATA]',
q'[IGNORE_OPTIM_EMBEDDED_HINTS]',
q'[OPTIMIZER_FEATURES_ENABLE('11.2.0.4')]',
q'[DB_VERSION('11.2.0.4')]',
q'[ALL_ROWS]',
q'[OUTLINE_LEAF(@"SEL$1")]',
q'[INDEX_RS_ASC(@"SEL$1" "T_MANUAL01"@"SEL$1" ("T_MANUAL01"."OBJECT_ID"))]',
q'[END_OUTLINE_DATA]');

替换为coe_xfr_sql_profile_fp5ng25383cvk_1705140427.sql脚本中的如下部分
。。。
h := SYS.SQLPROF_ATTR(
q'[BEGIN_OUTLINE_DATA]',
q'[IGNORE_OPTIM_EMBEDDED_HINTS]',
q'[OPTIMIZER_FEATURES_ENABLE('11.2.0.4')]',
q'[DB_VERSION('11.2.0.4')]',
q'[ALL_ROWS]',
q'[OUTLINE_LEAF(@"SEL$1")]',
q'[FULL(@"SEL$1" "T_MANUAL01"@"SEL$1")]',
q'[END_OUTLINE_DATA]');
。。。

这里也很好理解,其实manual sql profile也就是Outline Data的信息,manual sql profile就是用Outline Data来固化sql的执行计划。

替换完毕后再次执行脚本就将目标sql绑定了一个manual sql profile

SQL> @coe_xfr_sql_profile_5usjcvmsxj6mb_371934742.sql
...
SQL> DECLARE
  2  sql_txt CLOB;
  3  h       SYS.SQLPROF_ATTR;
  4  BEGIN
  5  sql_txt := q'[
  6  select /*+index(t_manual01 ind_manual_objid)
  7  */* from t_manual01 where object_id=1
  8  ]';
  9  h := SYS.SQLPROF_ATTR(
 10  q'[BEGIN_OUTLINE_DATA]',
 11  q'[IGNORE_OPTIM_EMBEDDED_HINTS]',
 12  q'[OPTIMIZER_FEATURES_ENABLE('11.2.0.4')]',
 13  q'[DB_VERSION('11.2.0.4')]',
 14  q'[ALL_ROWS]',
 15  q'[OUTLINE_LEAF(@"SEL$1")]',
 16  q'[FULL(@"SEL$1" "T_MANUAL01"@"SEL$1")]',
 17  q'[END_OUTLINE_DATA]');
 18  :signature := DBMS_SQLTUNE.SQLTEXT_TO_SIGNATURE(sql_txt);
 19  DBMS_SQLTUNE.IMPORT_SQL_PROFILE (
 20  sql_text    => sql_txt,
 21  profile     => h,
 22  name        => 'coe_5usjcvmsxj6mb_371934742',
 23  description => 'coe 5usjcvmsxj6mb 371934742 '||:signature||'',
 24  category    => 'DEFAULT',
 25  validate    => TRUE,
 26  replace     => TRUE,
 27  force_match => FALSE /* TRUE:FORCE (match even when different literals in SQL). FALSE:EXACT (similar to CURSOR_SHARING) */ );
 28  END;
 29  /

PL/SQL procedure successfully completed.

SQL> set autotrace traceonly;
SQL> select /*+index(t_manual01 ind_manual_objid)*/* from t_manual01 where object_id=1;

86320 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1705140427

--------------------------------------------------------------------------------
| Id  | Operation         | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |            |     1 |    98 |   344   (1)| 00:00:05 |
|*  1 |  TABLE ACCESS FULL| T_MANUAL01 |     1 |    98 |   344   (1)| 00:00:05 |
--------------------------------------------------------------------------------

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

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn