sqlprofile绑定执行计划实验测试

来源:这里教程网 时间:2026-03-03 16:12:56 作者:

sqlprofile在10g中出现,是9ioutline的升级版,即便现在11g 19c的大环境下,依然有较高的使用率。常用的场景为不改写sql的情况下,修改其执行计划。相较于11g的sqlbaseline,使用上个人感觉sqlbaseline简单点,因为可以指定sql_id,而sqlprofile只能指定sql_text。

难点部分其实只有一个,就是如何让原sql走正确的执行计划,比如怎么去加hint,加索引等。

详细测试步骤如下,可做参考:

1 构造实验环境

2 测试执行sql语句

3 这边我们手动优化下,让他走索引nl,可以看到,逻辑读少了很多。

4 获取语句执行的sql_id

5 替换执行计划

    5.1 步骤 1 获取优化后的 outline

    5.2 步骤 2 带入相关参数

   5.3 步骤3 查看是否生效,已经生效了,可以看到执行计划中有test1_troy_sql_profile这一条

6 查询或者删除sql profile

 

 

1 构造实验环境

SQL> create table t1 as select object_id,object_name from dba_objects where rownum<=50000;

Table created.

 

SQL> create table t2 as select * from dba_objects; 

Table created.

 

SQL>  create index t2_idx on t2(object_id);

Index created.

 

SQL> exec dbms_stats.gather_table_stats(user,'t1',cascade=>true,method_opt=>'for all columns size 1');

PL/SQL procedure successfully completed.

SQL> exec dbms_stats.gather_table_stats(user,'t2',cascade=>true,method_opt=>'for all columns size 1');

PL/SQL procedure successfully completed.

 

2 测试执行 sql 语句

SQL> set autot trace exp stat

SQL> set linesize 200

SQL> set pages 100

SQL>  select t1.*,t2.owner from t1,t2 where t1.object_name like '%T1%' and t1.object_id=t2.object_id;

36 rows selected.

Execution Plan

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

Plan hash value: 1838229974

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

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

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

|   0 | SELECT STATEMENT   |      |  2500 |   100K|   402   (1)| 00:00:05 |

|*  1 |  HASH JOIN         |      |  2500 |   100K|   402   (1)| 00:00:05 |

|*  2 |   TABLE ACCESS FULL| T1   |  2500 | 75000 |    66   (0)| 00:00:01 |

|   3 |   TABLE ACCESS FULL| T2   | 86260 |   926K|   336   (1)| 00:00:05 |

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

Predicate Information (identified by operation id):

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

   1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")

   2 - filter("T1"."OBJECT_NAME" LIKE '%T1%' AND "T1"."OBJECT_NAME" IS NOT NULL)

 

Statistics

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

         38  recursive calls

          0  db block gets

       1532  consistent gets

          0  physical reads

          0  redo size

       2132  bytes sent via SQL*Net to client

        545  bytes received via SQL*Net from client

          4  SQL*Net roundtrips to/from client

         10  sorts (memory)

          0  sorts (disk)

         36  rows processed

 

 

3 这边我们手动优化下,让他走索引nl,可以看到,逻辑读少了很多。

 select /*+use_nl(t1,t2) index(t2)*/t1.*,t2.owner from t1,t2 where t1.object_name like '%T1%' and t1.object_id=t2.object_id;

 

 Execution Plan

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

Plan hash value: 1022743391

 

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

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

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

|   0 | SELECT STATEMENT             |        |  2500 |   100K|  5067   (1)| 00:01:01 |

|   1 |  NESTED LOOPS                |        |  2500 |   100K|  5067   (1)| 00:01:01 |

|   2 |   NESTED LOOPS               |        |  2500 |   100K|  5067   (1)| 00:01:01 |

|*  3 |    TABLE ACCESS FULL         | T1     |  2500 | 75000 |    66   (0)| 00:00:01 |

|*  4 |    INDEX RANGE SCAN          | T2_IDX |     1 |       |     1   (0)| 00:00:01 |

|   5 |   TABLE ACCESS BY INDEX ROWID| T2     |     1 |    11 |     2   (0)| 00:00:01 |

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

 

Predicate Information (identified by operation id):

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

 

   3 - filter("T1"."OBJECT_NAME" LIKE '%T1%' AND "T1"."OBJECT_NAME" IS NOT

              NULL)

   4 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")

 

 

Statistics

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

          0  recursive calls

          0  db block gets

        306  consistent gets

          0  physical reads

          0  redo size

       2132  bytes sent via SQL*Net to client

        545  bytes received via SQL*Net from client

          4  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

         36  rows processed

 

4 获取语句执行的sql_id

select sql_id,sql_text from v$sql where sql_text like '% and t1.object_id=t2.object_id%'; (这一步骤没啥必要)

 

4zbqykx89yc8v

select t1.*,t2.owner from t1,t2 where t1.object_name like '%T1%' and t1.object_id=t2.object_id;

7a3t45wbn1299

select /*+use_nl(t1,t2) index(t2)*/t1.*,t2.owner from t1,t2 where t1.object_name like '%T1%' and t1.object_id=t2.object_id;

 

 

5 替换执行计划

 

5.1 步骤 1 获取优化后的 outline

explain plan for select /*+use_nl(t1,t2) index(t2)*/t1.*,t2.owner from t1,t2 where t1.object_name like '%T1%' and t1.object_id=t2.object_id;

select * from table(dbms_xplan.display(null,null,'outline'));

 

PLAN_TABLE_OUTPUT

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

Plan hash value: 1022743391

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

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

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

|   0 | SELECT STATEMENT             |        |  2500 |   100K|  5067   (1)| 00:01:01 |

|   1 |  NESTED LOOPS                |        |  2500 |   100K|  5067   (1)| 00:01:01 |

|   2 |   NESTED LOOPS               |        |  2500 |   100K|  5067   (1)| 00:01:01 |

|*  3 |    TABLE ACCESS FULL         | T1     |  2500 | 75000 |    66   (0)| 00:00:01 |

|*  4 |    INDEX RANGE SCAN          | T2_IDX |     1 |       |     1   (0)| 00:00:01 |

|   5 |   TABLE ACCESS BY INDEX ROWID| T2     |     1 |    11 |     2   (0)| 00:00:01 |

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

Outline Data

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

  /*+

      BEGIN_OUTLINE_DATA

      NLJ_BATCHING(@"SEL$1" "T2"@"SEL$1")

      USE_NL(@"SEL$1" "T2"@"SEL$1")

      LEADING(@"SEL$1" "T1"@"SEL$1" "T2"@"SEL$1")

      INDEX(@"SEL$1" "T2"@"SEL$1" ("T2"."OBJECT_ID"))

      FULL(@"SEL$1" "T1"@"SEL$1")

      OUTLINE_LEAF(@"SEL$1")

      ALL_ROWS

      DB_VERSION('11.2.0.4')

      OPTIMIZER_FEATURES_ENABLE('11.2.0.4')

      IGNORE_OPTIM_EMBEDDED_HINTS

      END_OUTLINE_DATA

  */

Predicate Information (identified by operation id):

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

   3 - filter("T1"."OBJECT_NAME" LIKE '%T1%' AND "T1"."OBJECT_NAME" IS NOT NULL)

   4 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")

37 rows selected.

 

5.2 步骤 2 带入相关参数

-- 使用 sql profile, 我们选取必要的 hint OK 了,其他的可以不要 , 如下, 多行的话 逗号隔开

-- 注意单引号要变成双引号,否则会提示格式错误

 

declare

  v_hints sys.sqlprof_attr;

begin

  v_hints := sys.sqlprof_attr(

  'USE_NL(@"SEL$1" "T2"@"SEL$1")',

  'LEADING(@"SEL$1" "T1"@"SEL$1" "T2"@"SEL$1")',

  'INDEX(@"SEL$1" "T2"@"SEL$1" ("T2"."OBJECT_ID"))'

  );

  dbms_sqltune.import_sql_profile('select t1.*,t2.owner from t1,t2 where t1.object_name like ''%T1%'' and t1.object_id=t2.object_id',

                                  v_hints,'test1_troy_sql_profile',

                                  force_match => true,replace=>true);

end;

/

 

成功会提示

PL/SQL procedure successfully completed.

 

 

5.3 步骤 3 查看是否生效,已经生效了,可以看到执行计划中有 test1_troy_sql_profile 这一条

 

Execution Plan

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

Plan hash value: 1022743391

 

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

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

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

|   0 | SELECT STATEMENT             |        |  2500 |   100K|  5067   (1)| 00:01:01 |

|   1 |  NESTED LOOPS                |        |  2500 |   100K|  5067   (1)| 00:01:01 |

|   2 |   NESTED LOOPS               |        |  2500 |   100K|  5067   (1)| 00:01:01 |

|*  3 |    TABLE ACCESS FULL         | T1     |  2500 | 75000 |    66   (0)| 00:00:01 |

|*  4 |    INDEX RANGE SCAN          | T2_IDX |     1 |       |     1   (0)| 00:00:01 |

|   5 |   TABLE ACCESS BY INDEX ROWID| T2     |     1 |    11 |     2   (0)| 00:00:01 |

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

 

Predicate Information (identified by operation id):

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

 

   3 - filter("T1"."OBJECT_NAME" LIKE '%T1%' AND "T1"."OBJECT_NAME" IS NOT NULL)

   4 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")

 

Note

-----

   - SQL profile "test1_troy_sql_profile" used for this statement

 

 

Statistics

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

          0  recursive calls

          0  db block gets

        306  consistent gets

          0  physical reads

          0  redo size

       2132  bytes sent via SQL*Net to client

        545  bytes received via SQL*Net from client

          4  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

         36  rows processed

 

  6 查询或者删除 sql profile

- 如果优化效果不理想,想要删除绑定的 sql_profile, 执行计划用的是未改变 slqprofile 之前的执行计划

-- 查看

select * from dba_sql_profiles;

 

SQL> BEGIN

  DBMS_SQLTUNE.DROP_SQL_PROFILE(name => 'test1_troy_sql_profile');

END;

相关推荐