dbms_spm之baseline FIXED=YES使用陷阱(执行计划不通用),严重影响系统;

SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE    11.2.0.3.0      Production
TNS for Linux: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production



--aiki下创建一实体表T1
SQL> create table t1 as select * from dba_objects where object_id is not null;

Table created.

SQL> create index idx_t1_id on t1(object_id);

Index created.

SQL> select status from t1 where object_id=33;

STATUS
-------
VALID

SQL> /

STATUS
-------
VALID

SQL> /

STATUS
-------
VALID

--生成SQL_ID,PHV(PLAN HASH VALUE)
SQL> @all

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  71v4d139gzpzq, child number 0
-------------------------------------
select status from t1 where object_id=33

Plan hash value: 190799060

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

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

   1 - SEL$1 / T1@SEL$1
   2 - SEL$1 / T1@SEL$1

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

   2 - access("OBJECT_ID"=33)

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - "STATUS"[VARCHAR2,7]
   2 - "T1".ROWID[ROWID,10]

Note
-----
   - dynamic sampling used for this statement (level=2)
  
--采用SPM绑定 
SQL>  declare
  2   aa binary_integer;
  3   begin
  4   aa:=DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(sql_id=>'71v4d139gzpzq',PLAN_HASH_VALUE=>190799060,FIXED=>'YES',ENABLED=>'YES');
  5   return ;
  6   end;
  7   /
 
PL/SQL procedure successfully completed.
--查看baseline视图,已经绑定计划
  1* select  SQL_TEXT,PLAN_NAME,ENABLED,ACCEPTED,FIXED from dba_sql_plan_baselines
SQL> /

SQL_TEXT                                           PLAN_NAME                      ENA ACC FIX
-------------------------------------------------- ------------------------------ --- --- ---
select status from t1 where object_id=33           SQL_PLAN_b6tztbgtkhqdt74b15d2b YES YES YES


--在Note部份可以看到baseline绑定已经生效,是走索引的
--SQL plan baseline SQL_PLAN_b6tztbgtkhqdt74b15d2b used for this statement
SQL> @all

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  71v4d139gzpzq, child number 1
-------------------------------------
select status from t1 where object_id=33

Plan hash value: 190799060

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

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

   1 - SEL$1 / T1@SEL$1
   2 - SEL$1 / T1@SEL$1

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

   2 - access("OBJECT_ID"=33)

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - "STATUS"[VARCHAR2,7]
   2 - "T1".ROWID[ROWID,10]

Note
-----
   - dynamic sampling used for this statement (level=2)
   - SQL plan baseline SQL_PLAN_b6tztbgtkhqdt74b15d2b used for this statement
--看下内存中此SQL的游标分布,子游标号为2,0为父游标,phv:190799060
SQL_ID        CHILD_NUMBER PLAN_HASH_VALUE
------------- ------------ ---------------
71v4d139gzpzq            0       190799060
71v4d139gzpzq            2       190799060
   

--在用户AIKI2下创建一实体表T1,但无索引
--可以看到baseline对它不生效,因为

create table t1 as select * from dba_objects where object_Id is not null;
   
SQL> select status from t1 where object_id=33;

STATUS
-------
VALID

SQL> select status from t1 where object_id=33;

STATUS
-------
VALID

SQL> select status from t1 where object_id=33;

STATUS
-------
VALID

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  71v4d139gzpzq, child number 1
-------------------------------------
select status from t1 where object_id=33

Plan hash value: 3617692013

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |       |       |   300 (100)|          |
|*  1 |  TABLE ACCESS FULL| T1   |    12 |   216 |   300   (1)| 00:00:04 |
--------------------------------------------------------------------------

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

   1 - SEL$1 / T1@SEL$1

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

   1 - filter("OBJECT_ID"=33)

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - "STATUS"[VARCHAR2,7]

Note
-----
   - dynamic sampling used for this statement (level=2)

--再次检查下可以发现子游标为2的游标已经被刷出内存,而取代它的是子游标为1的游标,phv:3617692013

select sql_id,child_number,plan_hash_value from v$sql where sql_id='71v4d139gzpzq'

SQL_ID        CHILD_NUMBER PLAN_HASH_VALUE
------------- ------------ ---------------
71v4d139gzpzq            0       190799060
71v4d139gzpzq            1      3617692013

--小结下:可以发现两条SQL_ID一样SQL,执行计划不同而导致两个执行计划的游标相互竞争,有你没我;
--严重后果:在我国很多企业都是按省市下的地市来做业务,同一个库中包含多个地市的模型,而且大多
--模型结果相同;当某SQL由于性能原因而采用SPM进行稳固,且fixes=>yes时得万分小心,否则将引由于
--其中1SQL游标被刷出而再次高并发登录时产生大规模的library cache lock事件,导致CPU资源被耗光;
--这个已经碰到过一次了;

=》我们来看第2种情况,当两者之间也是SQL_ID相同而模型结构不同导致的执行计划不同时的情况;

AIKI2用户建为视图:
SQL> create view t2 as select distinct object_id,status,owner from dba_objects where object_id is not null;
View created.

AIKI用户建为实体表:

SQL> create table t2 as select object_id,status,owner from dba_objects where object_id is not null;

Table created.


--AIKI用户下运行,sql_id:d7y1m4pt52xwd,phv:1513984157
select status from t2 where object_id=55;

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  d7y1m4pt52xwd, child number 0
-------------------------------------
select status from t2 where object_id=55

Plan hash value: 1513984157

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |       |       |    67 (100)|          |
|*  1 |  TABLE ACCESS FULL| T2   |     3 |    54 |    67   (2)| 00:00:01 |
--------------------------------------------------------------------------

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

   1 - SEL$1 / T2@SEL$1

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

   1 - filter("OBJECT_ID"=55)

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - "STATUS"[VARCHAR2,7]

Note
-----
   - dynamic sampling used for this statement (level=2)


32 rows selected.
--进行计划的稳固绑定
SQL>  declare
  2   aa binary_integer;
  3   begin
  4   aa:=DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(sql_id=>'d7y1m4pt52xwd',PLAN_HASH_VALUE=>1513984157,FIXED=>'YES',ENABLED=>'YES');
  5   return ;
  6   end;
  7   /
 
PL/SQL procedure successfully completed.
--查看已经生效
SQL> select  SQL_TEXT,PLAN_NAME,ENABLED,ACCEPTED,FIXED from dba_sql_plan_baselines
  2  /

SQL_TEXT                                           PLAN_NAME                      ENA ACC FIX
-------------------------------------------------- ------------------------------ --- --- ---
select status from t2 where object_id=55           SQL_PLAN_7j9ssum4sn3fkb860bcf2 YES YES YES

SQL> @all

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  d7y1m4pt52xwd, child number 1
-------------------------------------
select status from t2 where object_id=55

Plan hash value: 1513984157

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |       |       |    67 (100)|          |
|*  1 |  TABLE ACCESS FULL| T2   |     3 |    54 |    67   (2)| 00:00:01 |
--------------------------------------------------------------------------

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

   1 - SEL$1 / T2@SEL$1

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

   1 - filter("OBJECT_ID"=55)

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - "STATUS"[VARCHAR2,7]

Note
-----
   - dynamic sampling used for this statement (level=2)
   - SQL plan baseline SQL_PLAN_7j9ssum4sn3fkb860bcf2 used for this statement


33 rows selected.
--检查下当前的游标情况:SQL_ID:d7y1m4pt52xwd,子游标:1,PHV:1513984157
SQL> select sql_id,child_number,plan_hash_value from v$sql where sql_id='d7y1m4pt52xwd';

SQL_ID        CHILD_NUMBER PLAN_HASH_VALUE
------------- ------------ ---------------
d7y1m4pt52xwd            0      1513984157
d7y1m4pt52xwd            1      1513984157

--在AIKI2用户上运行
SQL> select status from t2 where object_id=55;

STATUS
-------
VALID

SQL> /

STATUS
-------
VALID

SQL> /

STATUS
-------
VALID

SQL> /

STATUS
-------
VALID

SQL> /

SQL_ID        CHILD_NUMBER PLAN_HASH_VALUE
------------- ------------ ---------------
d7y1m4pt52xwd            0      1513984157
d7y1m4pt52xwd            2      3629752164



aiki下再次执行,可以看到情况和第一次实验完全相同;
SQL> select status from t2 where object_id=55;

STATUS
-------
VALID

SQL> /

STATUS
-------
VALID

SQL> /

SQL_ID        CHILD_NUMBER PLAN_HASH_VALUE
------------- ------------ ---------------
d7y1m4pt52xwd            0      1513984157
d7y1m4pt52xwd            1      1513984157

	

--可以看到情况与上面一样;

这里纠正个问题,昨天写得不全面重改了以下部份;
以于FIXED=YES的情况,才会导到多个会话间相互挤兑而引起的高并发下的大量library cache lock事件;
由于实验过于繁琐冗长,我这里只写下小结,详细的证明可以自行去实验下;
假定会话1叫S1,会话2叫S2,以及它们的计划和通用性;如下所示:
会话    SQL_ID    phv    FIXED    S1兼容S2       S1不兼容S2
S1       sqlid1         phv1    YES    不相互挤兑       相互挤兑
S2       sqlid1         phv2    NO      不相互挤兑       相互挤兑

补充备注:

当S1的FIXED=NO,S2不兼容时会自动将它的执行计划添加到BSLINE,默认accepted=no,但不发生挤兑;

当S1的FIXED=NO,S2兼容时会自动将它的最优执行计划添加到BSLINE,默认accepted=no,但不发生挤兑,同时使用S1的执行计划而不是它的最优计划;

当S1,S2都在BSLINE时FIXED=YES OR NO时两者是平等的;

这个实验最好自己去试下才会清楚,容易搞混;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
grant execute on dbms_crypto to system; declare input_string VARCHAR2 (200) := 'Secret Message'; output_string VARCHAR2(2000); encrypted_raw RAW(2000); decrypted_raw RAW(2000); num_key_bytes NUMBER := 256/8; key_bytes_raw RAW(32); encryption_type PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_AES256 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5; begin DBMS_OUTPUT.PUT_LINE(input_string); key_bytes_raw := DBMS_CRYPTO.RANDOMBYTES(num_key_bytes); encrypted_raw := DBMS_CRYPTO.ENCRYPT ( src => UTL_I18N.STRING_TO_RAW(input_string, 'AL32UTF8'), typ => encryption_type, key => key_bytes_raw ); decrypted_raw := DBMS_CRYPTO.DECRYPT ( src => encrypted_raw, typ => encryption_type, key => key_bytes_raw ); output_string := UTL_I18N.RAW_TO_CHAR(decrypted_raw, 'AL32UTF8'); DBMS_OUTPUT.PUT_LINE(output_string); end; declare l_src_data varchar2(20); l_type pls_integer :=DBMS_CRYPTO.ENCRYPT_AES128 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5; l_key varchar2(20) :='0123456789123456'; l_encval raw(2000); CURSOR secret_cursor IS select phonenumber from customer; begin OPEN secret_cursor; LOOP FETCH secret_cursor INTO l_src_data; l_encval :=dbms_crypto.encrypt( src=>utl_i18n.string_to_raw(l_src_data,'AL32UTF8'), typ=>l_type, key=>utl_i18n.string_to_raw(l_key,'AL32UTF8')); DBMS_OUTPUT.PUT_LINE (l_encval); EXIT WHEN secret_cursor%NOTFOUND; END LOOP; CLOSE secret_cursor; end; declare ;_src_data row(100) :=hextoraw("190248129038903853275ijdkvjkad'); l_type pls_integer :=dbms_crypto.encrypt_aes128+ + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5; l_key varchar2(20) :='0123456789123456'; l_decval raw(200); begin l_decval :=dbms_crypto.decrypt( src=>l_src_data, typ=>l_type, key=>utl_i18n.string_to_raw(l_key,'AL32UTF8')); end; SELECT Price FROM PRODUCT WHERE ProductID = 5;修正这一段代码
最新发布
05-26
以下是修正后的代码: ``` grant execute on dbms_crypto to system; -- 第一个代码块 declare input_string VARCHAR2 (200) := 'Secret Message'; output_string VARCHAR2(2000); encrypted_raw RAW(2000); decrypted_raw RAW(2000); num_key_bytes NUMBER := 256/8; key_bytes_raw RAW(32); encryption_type PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_AES256 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5; begin DBMS_OUTPUT.PUT_LINE(input_string); key_bytes_raw := DBMS_CRYPTO.RANDOMBYTES(num_key_bytes); encrypted_raw := DBMS_CRYPTO.ENCRYPT(src => UTL_I18N.STRING_TO_RAW(input_string, 'AL32UTF8'), typ => encryption_type, key => key_bytes_raw); decrypted_raw := DBMS_CRYPTO.DECRYPT(src => encrypted_raw, typ => encryption_type, key => key_bytes_raw); output_string := UTL_I18N.RAW_TO_CHAR(decrypted_raw, 'AL32UTF8'); DBMS_OUTPUT.PUT_LINE(output_string); end; -- 第二个代码块 declare l_src_data varchar2(20); l_type pls_integer := DBMS_CRYPTO.ENCRYPT_AES128 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5; l_key varchar2(20) := '0123456789123456'; l_encval raw(2000); cursor secret_cursor is select phonenumber from customer; begin open secret_cursor; loop fetch secret_cursor into l_src_data; exit when secret_cursor%notfound; l_encval := dbms_crypto.encrypt(src => utl_i18n.string_to_raw(l_src_data,'AL32UTF8'), typ => l_type, key => utl_i18n.string_to_raw(l_key,'AL32UTF8')); dbms_output.put_line(l_encval); end loop; close secret_cursor; end; -- 第三个代码块 declare l_src_data raw(100) := hextoraw('190248129038903853275ijdkvjkad'); l_type pls_integer := DBMS_CRYPTO.ENCRYPT_AES128 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5; l_key varchar2(20) := '0123456789123456'; l_decval raw(200); begin l_decval := dbms_crypto.decrypt(src => l_src_data, typ => l_type, key => utl_i18n.string_to_raw(l_key,'AL32UTF8')); end; -- SQL 查询语句 SELECT Price FROM PRODUCT WHERE ProductID = 5; ``` 注意:第三个代码块中的 `l_src_data` 变量的赋值语句中,修正了单引号和双引号的不匹配问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值