如何使用SQL PROFILE固定SHARED POOL中的执行计划

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用SQL PROFILE固定SHARED POOL中的执行计划相关的知识,希望对你有一定的参考价值。

参考技术A 执行计划
----------------------------------------------------------
Plan hash value: 3958077978

-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 35 (3)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 9 | | |
|* 2 | INDEX FAST FULL SCAN| IDX_CPIC_01 | 19221 | 168K| 35 (3)| 00:00:01 |
-------------------------------------------------------------------------------------

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

2 - filter("OBJECT_TYPE"='SYNONYM')

SQL> set autot off
SQL> column sql_text format a40
SQL> select sql_id,sql_text from v$sql where sql_text like 'select count(1) from test where object_type=%';

SQL_ID SQL_TEXT
------------- ----------------------------------------
8ma7qaqmmt5bn select count(1) from test where object_t
ype='SYNONYM'

SQL> select plan_hash_value from v$sql_plan where sql_id='8ma7qaqmmt5bn' and rownum=1;

PLAN_HASH_VALUE
---------------
3958077978

SQL>

下面我们用coe_xfr_sql_profile.sql脚本生成创建SQL PROFILE的脚本。

SQL> @coe_xfr_sql_profile.sql 8ma7qaqmmt5bn 3958077978

Parameter 1:
SQL_ID (required)

PLAN_HASH_VALUE AVG_ET_SECS
--------------- -----------
3958077978

Parameter 2:
PLAN_HASH_VALUE (required)

Values passed to coe_xfr_sql_profile:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SQL_ID : "8ma7qaqmmt5bn"
PLAN_HASH_VALUE: "3958077978"

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_8ma7qaqmmt5bn_3958077978.sql
on TARGET system in order to create a custom SQL Profile
with plan 3958077978 linked to adjusted sql_text.

COE_XFR_SQL_PROFILE completed.
SQL>

生成的脚本coe_xfr_sql_profile_8ma7qaqmmt5bn_3958077978.sql内容如下:

SPO coe_xfr_sql_profile_8ma7qaqmmt5bn_3958077978.log;
SET ECHO ON TERM ON LIN 2000 TRIMS ON NUMF 99999999999999999999;
REM
REM $Header: 215187.1 coe_xfr_sql_profile_8ma7qaqmmt5bn_3958077978.sql 11.4.4.4 2013/01/11 carlos.sierra $
REM
REM Copyright (c) 2000-2012, Oracle Corporation. All rights reserved.
REM
REM AUTHOR
REM carlos.sierra@oracle.com
REM
REM SCRIPT
REM coe_xfr_sql_profile_8ma7qaqmmt5bn_3958077978.sql
REM
REM DESCRIPTION
REM This script is generated by coe_xfr_sql_profile.sql
REM It contains the SQL*Plus commands to create a custom
REM SQL Profile for SQL_ID 8ma7qaqmmt5bn based on plan hash
REM value 3958077978.
REM The custom SQL Profile to be created by this script
REM will affect plans for SQL commands with signature
REM matching the one for SQL Text below.
REM Review SQL Text and adjust accordingly.
REM
REM PARAMETERS
REM None.
REM
REM EXAMPLE
REM SQL> START coe_xfr_sql_profile_8ma7qaqmmt5bn_3958077978.sql;
REM
REM NOTES
REM 1. Should be run as SYSTEM or SYSDBA.
REM 2. User must have CREATE ANY SQL PROFILE privilege.
REM 3. SOURCE and TARGET systems can be the same or similar.
REM 4. To drop this custom SQL Profile after it has been created:
REM EXEC DBMS_SQLTUNE.DROP_SQL_PROFILE('coe_8ma7qaqmmt5bn_3958077978');
REM 5. Be aware that using DBMS_SQLTUNE requires a license
REM for the Oracle Tuning Pack.
REM 6. If you modified a SQL putting Hints in order to produce a desired
REM Plan, you can remove the artifical Hints from SQL Text pieces below.
REM By doing so you can create a custom SQL Profile for the original
REM SQL but with the Plan captured from the modified SQL (with Hints).
REM
WHENEVER SQLERROR EXIT SQL.SQLCODE;
REM
VAR signature NUMBER;
VAR signaturef NUMBER;
REM
DECLARE
sql_txt CLOB;
h SYS.SQLPROF_ATTR;
PROCEDURE wa (p_line IN VARCHAR2) IS
BEGIN
DBMS_LOB.WRITEAPPEND(sql_txt, LENGTH(p_line), p_line);
END wa;
BEGIN
DBMS_LOB.CREATETEMPORARY(sql_txt, TRUE);
DBMS_LOB.OPEN(sql_txt, DBMS_LOB.LOB_READWRITE);
-- SQL Text pieces below do not have to be of same length.
-- So if you edit SQL Text (i.e. removing temporary Hints),
-- there is no need to edit or re-align unmodified pieces.
wa(q'[select count(1) from test where object_type='SYNONYM' ]');
DBMS_LOB.CLOSE(sql_txt);
h := SYS.SQLPROF_ATTR(
q'[BEGIN_OUTLINE_DATA]',
q'[IGNORE_OPTIM_EMBEDDED_HINTS]',
q'[OPTIMIZER_FEATURES_ENABLE('10.2.0.1')]',
q'[ALL_ROWS]',
q'[OUTLINE_LEAF(@"SEL$1")]',
q'[INDEX_FFS(@"SEL$1" "TEST"@"SEL$1" ("TEST"."OBJECT_TYPE"))]',
q'[END_OUTLINE_DATA]');
:signature := DBMS_SQLTUNE.SQLTEXT_TO_SIGNATURE(sql_txt);
:signaturef := DBMS_SQLTUNE.SQLTEXT_TO_SIGNATURE(sql_txt, TRUE);
DBMS_SQLTUNE.IMPORT_SQL_PROFILE (
sql_text => sql_txt,
profile => h,
name => 'coe_8ma7qaqmmt5bn_3958077978',
description => 'coe 8ma7qaqmmt5bn 3958077978 '||:signature||' '||:signaturef||'',
category => 'DEFAULT',
validate => TRUE,
replace => TRUE,
force_match => FALSE /* TRUE:FORCE (match even when different literals in SQL). FALSE:EXACT (similar to CURSOR_SHARING) */ );
DBMS_LOB.FREETEMPORARY(sql_txt);
END;
/
WHENEVER SQLERROR CONTINUE
SET ECHO OFF;
PRINT signature
PRINT signaturef
PRO
PRO ... manual custom SQL Profile has been created
PRO
SET TERM ON ECHO OFF LIN 80 TRIMS OFF NUMF "";
SPO OFF;
PRO
PRO COE_XFR_SQL_PROFILE_8ma7qaqmmt5bn_3958077978 completed

我们可以直接使用这个脚本,也可以自己根据实际情况进行修改后在执行。

SQL>@coe_xfr_sql_profile_8ma7qaqmmt5bn_3958077978.sql
SQL>REM
SQL>REM $Header: 215187.1 coe_xfr_sql_profile_8ma7qaqmmt5bn_3958077978.sql 11.4.4.4 2013/01/11 carlos.sierra $
SQL>REM
SQL>REM Copyright (c) 2000-2012, Oracle Corporation. All rights reserved.
SQL>REM
SQL>REM AUTHOR
SQL>REM carlos.sierra@oracle.com
SQL>REM
SQL>REM SCRIPT
SQL>REM coe_xfr_sql_profile_8ma7qaqmmt5bn_3958077978.sql
SQL>REM
SQL>REM DESCRIPTION
SQL>REM This script is generated by coe_xfr_sql_profile.sql
SQL>REM It contains the SQL*Plus commands to create a custom
SQL>REM SQL Profile for SQL_ID 8ma7qaqmmt5bn based on plan hash
SQL>REM value 3958077978.
SQL>REM The custom SQL Profile to be created by this script
SQL>REM will affect plans for SQL commands with signature
SQL>REM matching the one for SQL Text below.
SQL>REM Review SQL Text and adjust accordingly.
SQL>REM
SQL>REM PARAMETERS
SQL>REM None.
SQL>REM
SQL>REM EXAMPLE
SQL>REM SQL> START coe_xfr_sql_profile_8ma7qaqmmt5bn_3958077978.sql;
SQL>REM
SQL>REM NOTES
SQL>REM 1. Should be run as SYSTEM or SYSDBA.
SQL>REM 2. User must have CREATE ANY SQL PROFILE privilege.
SQL>REM 3. SOURCE and TARGET systems can be the same or similar.
SQL>REM 4. To drop this custom SQL Profile after it has been created:
SQL>REM EXEC DBMS_SQLTUNE.DROP_SQL_PROFILE('coe_8ma7qaqmmt5bn_3958077978');
SQL>REM 5. Be aware that using DBMS_SQLTUNE requires a license
SQL>REM for the Oracle Tuning Pack.
SQL>REM 6. If you modified a SQL putting Hints in order to produce a desired
SQL>REM Plan, you can remove the artifical Hints from SQL Text pieces below.
SQL>REM By doing so you can create a custom SQL Profile for the original
SQL>REM SQL but with the Plan captured from the modified SQL (with Hints).
SQL>REM
SQL>WHENEVER SQLERROR EXIT SQL.SQLCODE;
SQL>REM
SQL>VAR signature NUMBER;
SQL>VAR signaturef NUMBER;
SQL>REM
SQL>DECLARE
2 sql_txt CLOB;
3 h SYS.SQLPROF_ATTR;
4 PROCEDURE wa (p_line IN VARCHAR2) IS
5 BEGIN
6 DBMS_LOB.WRITEAPPEND(sql_txt, LENGTH(p_line), p_line);
7 END wa;
8 BEGIN
9 DBMS_LOB.CREATETEMPORARY(sql_txt, TRUE);
10 DBMS_LOB.OPEN(sql_txt, DBMS_LOB.LOB_READWRITE);
11 -- SQL Text pieces below do not have to be of same length.
12 -- So if you edit SQL Text (i.e. removing temporary Hints),
13 -- there is no need to edit or re-align unmodified pieces.
14 wa(q'[select count(1) from test where object_type='SYNONYM' ]');
15 DBMS_LOB.CLOSE(sql_txt);
16 h := SYS.SQLPROF_ATTR(
17 q'[BEGIN_OUTLINE_DATA]',
18 q'[IGNORE_OPTIM_EMBEDDED_HINTS]',
19 q'[OPTIMIZER_FEATURES_ENABLE('10.2.0.1')]',
20 q'[ALL_ROWS]',
21 q'[OUTLINE_LEAF(@"SEL$1")]',
22 q'[INDEX_FFS(@"SEL$1" "TEST"@"SEL$1" ("TEST"."OBJECT_TYPE"))]',
23 q'[END_OUTLINE_DATA]');
24 :signature := DBMS_SQLTUNE.SQLTEXT_TO_SIGNATURE(sql_txt);
25 :signaturef := DBMS_SQLTUNE.SQLTEXT_TO_SIGNATURE(sql_txt, TRUE);
26 DBMS_SQLTUNE.IMPORT_SQL_PROFILE (
27 sql_text => sql_txt,
28 profile => h,
29 name => 'coe_8ma7qaqmmt5bn_3958077978',
30 description => 'coe 8ma7qaqmmt5bn 3958077978 '||:signature||' '||:signaturef||'',
31 category => 'DEFAULT',
32 validate => TRUE,
33 replace => TRUE,
34
force_match => FALSE /* TRUE:FORCE (match even when different
literals in SQL). FALSE:EXACT (similar to CURSOR_SHARING) */ );
35 DBMS_LOB.FREETEMPORARY(sql_txt);
36 END;
37 /

PL/SQL 过程已成功完成。

如何使用shared pool latch?

使用那个shared pool latch.txt

--//我的测试环境很小,仅仅1个shared pool latch.如果存在多个,一条sql语句应该会使用那个shared pool latch.
--//按照前面的学习,猜测应该于hash_value , bucket_size , _kghdsidx_count 相关,测试看看。
--//注:一般缺省bucket_size =2^(9+8) =131072

1.环境:
SCOTT@book> @ ver1
PORT_STRING VERSION BANNER


x86_64/Linux 2.4.xx 11.2.0.4.0 Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

SCOTT@book> select * from dept where deptno=20;

DEPTNO DNAME          LOC

    20 RESEARCH       DALLAS

SCOTT@book> @ hash
HASH_VALUE SQL_ID CHILD_NUMBER HASH_HEX


95129850 80baj2c2ur47u 0 5ab90fa

SYS@book> @ hide _kgl_bucket_count
NAME DESCRIPTION DEFAULT_VALUE SESSION_VALUE SYSTEM_VALUE ISSES ISSYS_MOD


_kgl_bucket_count Library cache hash table bucket count (2^_kgl_bucket_count * 256) TRUE 9 9 FALSE FALSE

SYS@book> alter system set "_kghdsidx_count"=7 scope=spfile;
System altered.

--//重启数据库略

SELECT addr

    ,latch#
    ,child#
    ,level#
    ,name
    ,gets
    ,sleeps
    ,immediate_gets
    ,immediate_misses
    ,spin_gets
FROM V$LATCH_CHILDREN

WHERE name LIKE \'shared pool\'
ORDER BY addr;

ADDR LATCH# CHILD# LEVEL# NAME GETS SLEEPS IMMEDIATE_GETS IMMEDIATE_MISSES SPIN_GETS


000000006010D9A0 336 1 7 shared pool 10126 0 0 0 29
000000006010DA40 336 2 7 shared pool 6220 0 0 0 5
000000006010DAE0 336 3 7 shared pool 8610 0 0 0 7
000000006010DB80 336 4 7 shared pool 7817 0 0 0 21
000000006010DC20 336 5 7 shared pool 7446 0 0 0 18
000000006010DCC0 336 6 7 shared pool 7302 1 0 0 7
000000006010DD60 336 7 7 shared pool 6347 0 0 0 3
7 rows selected.
--//记下7个addr地址. 000000006010D9A0 000000006010DA40 000000006010DAE0 000000006010DB80 000000006010DC20 000000006010DCC0 000000006010DD60.

2.测试:
--//编辑gdb脚本:
$ cat shared_pool.gdb
set pagination off

break kslgetl if $rdi==0X6010D9A0
commands

silent
printf "child#=1 kslgetl %x, %d, %d, %d\\n", $rdi, $rsi, $rdx, $rcx
c

end

break kslgetl if $rdi==0X6010DA40
commands

silent
printf "child#=2 kslgetl %x, %d, %d, %d\\n", $rdi, $rsi, $rdx, $rcx
c

end

break kslgetl if $rdi==0X6010DAE0
commands

silent
printf "child#=3 kslgetl %x, %d, %d, %d\\n", $rdi, $rsi, $rdx, $rcx
c

end

break kslgetl if $rdi==0X6010DB80
commands

silent
printf "child#=4 kslgetl %x, %d, %d, %d\\n", $rdi, $rsi, $rdx, $rcx
c

end

break kslgetl if $rdi==0X6010DC20
commands

silent
printf "child#=5 kslgetl %x, %d, %d, %d\\n", $rdi, $rsi, $rdx, $rcx
c

end

break kslgetl if $rdi==0X6010DCC0
commands

silent
printf "child#=6 kslgetl %x, %d, %d, %d\\n", $rdi, $rsi, $rdx, $rcx
c

end

break kslgetl if $rdi==0X6010DD60
commands

silent
printf "child#=7 kslgetl %x, %d, %d, %d\\n", $rdi, $rsi, $rdx, $rcx
c

end

--//先执行Select * from dept where deptno=20;,desc dept多次,避免一些递归.
--// hash_value % bucket_size % _kghdsidx_count
--// 95129850 % 7 = 4
--// 95129850 % 131072 % 7 = 2

--//验证看看使用那个shared pool latch.
--//session 1:
SCOTT@book(1,7)> @ spid

   SID    SERIAL# PROCESS                  SERVER    SPID       PID  P_SERIAL# C50

     1          7 4691                     DEDICATED 4692        24          4 alter system kill session \'1,7\' immediate;

SCOTT@book> select * from dept where deptno=20;

DEPTNO DNAME          LOC

    20 RESEARCH       DALLAS

--//session 2:
$ gdb -p 4692 -x shared_pool.gdb

...
Breakpoint 1 at 0x93f97a8
(gdb) c
...
child#=3 kslgetl 6010dae0, 1, 0, 4039
child#=3 kslgetl 6010dae0, 1, 0, 3980
child#=3 kslgetl 6010dae0, 1, 0, 4039
child#=3 kslgetl 6010dae0, 1, 2132183136, 3991
--//6010dae0 对应的就是CHILD#=3.
--//估计 hash_value % bucket_size % _kghdsidx_count + 1 . 或者 _kghdsidx_count-hash_value % _kghdsidx_count(不对!!)
--//可以大致推测使用的计算公式是 hash_value % bucket_size % _kghdsidx_count + 1
--//多找几条sql语句验证看看。

3.继续验证看看.
--//注意验证前最好执行select sysdate from dual;多次排除链接
--//因为11g下sqlplus执行后不会马上释放光标,导致看到的是前面的语句,这样可能不对。

--//session 3,主要目的确定hash_value:

SCOTT@book> select * from dept where deptno=10;

DEPTNO DNAME          LOC

    10 ACCOUNTING     NEW YORK

SCOTT@book> @ hash
HASH_VALUE SQL_ID CHILD_NUMBER HASH_HEX


911274289 4xamnunv51w9j 1 3650f131
--// 911274289 % 131072 % 7 +1 = 6

SCOTT@book> select * from dept where deptno=30;

DEPTNO DNAME          LOC

    30 SALES          CHICAGO

SCOTT@book>
HASH_VALUE SQL_ID CHILD_NUMBER HASH_HEX


69952862 816w0g822qtay 0 42b655e
--// 69952862 % 131072 % 7+1 = 4

SCOTT@book> select * from dept where deptno=40;

DEPTNO DNAME          LOC

    40 OPERATIONS     BOSTON

HASH_VALUE SQL_ID CHILD_NUMBER HASH_HEX


3912471479 14ymr4znm74xr 0 e93393b7
--// 3912471479 % 131072 % 7 +1 = 4

SCOTT select * from dept where deptno=50;
no rows selected

HASH_VALUE SQL_ID CHILD_NUMBER HASH_HEX


1927948053 bswp9zttfn9sp 0 72ea2715
--//1927948053 % 131072 % 7 +1 = 3

--//session 1:
--//再次提醒执行select sysdate from dual;多次。
select sysdate from dual;
select sysdate from dual;
select sysdate from dual;
select sysdate from dual;
select sysdate from dual;
select * from dept where deptno=10;
select sysdate from dual;
select sysdate from dual;
select * from dept where deptno=30;
select sysdate from dual;
select sysdate from dual;
select * from dept where deptno=40;
select sysdate from dual;
select sysdate from dual;
select * from dept where deptno=50;

--//session 2:
$ gdb -p 4692 -x shared_pool.gdb
...
child#=6 kslgetl 6010dcc0, 1, 0, 3980 => select * from dept where deptno=10; => child#=6
...
child#=4 kslgetl 6010db80, 1, 0, 3980 => select * from dept where deptno=30; => child#=4
...
child#=4 kslgetl 6010db80, 1, 0, 3980 => select * from dept where deptno=40; => child#=4
...
child#=3 kslgetl 6010dae0, 1, 0, 4039 => select * from dept where deptno=50; => child#=3

--//OK.都能对上。

总结:
--//说明一条sql语句会使用 其sql语句的 hash_value % bucket_size % _kghdsidx_count +1 的 shared pool latch.

以上是关于如何使用SQL PROFILE固定SHARED POOL中的执行计划的主要内容,如果未能解决你的问题,请参考以下文章

固定执行计划-使用coe_xfr_sql_profile

Oracle固定SQL的执行计划---SQL Profile

Oracle ---- 固定执行计划之SqlProfile

如何从 Typescript 中的固定对象的键创建映射类型

如何使用iOS 开发证书 和 Profile 文件

如何使用iOS 开发证书 和 Profile 文件