zoukankan      html  css  js  c++  java
  • SPA 介绍

    SQL 性能分析器(SPA)工具概览
          


    作为 Oracle Real Application Testing 选件/特性,这篇文章将提供一个关于 SQL 性能分析器(SPA)工具的简要概览。这是此系列的第一部分。第二部分于下个月继续讲述数据库捕获和重演。关于 SPA 的详细信息可参考:

    数据库测试指南

    DBA 的一个重要工作是确保在一个计划内的变更安排后,当前生产环境负载和 SQL 执行计划可以持续平滑运行。变更可能包含数据库升级、增加一个新索引或改变一个特定的数据库参数。 SPA 工具作为 Oracle Real Application Testing 选件的一部分提供,允许将生产环境负载中的 SQL 拿到测试环境的目标数据库运行,所以可以通过比对结果识别退化的性能问题,并在迁移、升级或特定系统变更之前修复。如果您计划使用数据库重演特性,在运行重演之前使用 SPA 是 Oracle 建议的最佳实践。目标是在数据库重演之前识别和修复所有的 SQL 性能退化,所以我们可以只关注重演特性中的并发和吞吐量 。SQL 性能分析器使用 SQL 调优集(STS)作为输入,STS 已经存在了很长一段时间了,这允许 DBA 提取现有生产环境的 SQL 语句工作负载并在节省时间和资源的前提下轻松比对一组变更前和变更后的执行结果。 一个 SQL 调优集(STS)是一个包含了一系列从工作负载中得来的 SQL 语句集及其执行上下文信息(例如用户和绑定变量、执行的统计信息和执行计划)的数据库对象。关于 STS 的更多信息,请参考: Managing SQL Tuning Sets

    注: SQL 性能分析器需要 Oracle Real Application Testing 许可. 更多信息,请参考:  Oracle Database Licensing Information.

    如下清单提供了一些 DBA 考虑使用 SPA 工具的常见场景。 

    使用场景


    1.    数据库升级 – 一个新版本数据库意味着一个新版本的优化器。DBA 能在升级生产系统之前主动发现任何 SQL 性能退化。
    2.    部署一个补丁 – 您可能会部署一个与性能或优化器相关的特定修复的补丁。使用 SPA 来检查您的生产环境 SQL 负载能帮助您验证这个补丁不会引起任何 SQL 性能退化。
    3.    数据库初始化参数变更 - 有各种各样的数据库参数可能影响性能,所以这是 SPA 用处的一个很好的场景。
    4.    Schema 变更例如增加索引 – schema 变更和修改,如增加索引会直接影响优化器的决定和计划。SPA 可用来测试这些变更并确保不会引入负面影响。
    5.    改变或刷新优化器统计信息 – 优化器统计信息直接关系到优化器的决策和执行计划的生成,您可以使用 SPA 来测试新的统计信息和设置来确保它们不会引起 SQL 性能退化。 

    使用 SPA 包括执行以下工作流文档/步骤。SPA 工具完全集成到 Oracle12c Cloud Control 中,Oracle 也提供了一个名为 DBMS_SQLPA 的 PLSQL 包来允许 DBA 使用 PL/SQL 实施这些步骤。这个工作流使用了一个迭代的过程来执行、对比和分析、以及修复这些退化。DBA 可使用诸如 SQL 执行计划基线或 SQL 调优顾问等工具/特性来修复 SPA 发现的坏或退化的 SQL 语句。

    SPA 工作流
    1.    捕捉您想要分析的生产系统的 SQL 工作负载,并将其保存为一个 SQL 调优集。
    2.    设置目标测试系统(这应该尽可能多地和生产系统一致)。
    3.    在测试系统创建一个 SPA 任务。

    Image

    4.    构建变更前 SPA 任务。
    5.    进行系统变更。
    6.    构建变更后 SPA 任务。                                                              
    7.    对比和分析变更前后的性能数据。
    8.    调优或修复任何退化的 SQL 语句。
    9.    重复地6~8步,直到 SQL 性能在测试系统上可接受。

    出于本文的目的,我们将通过一个简单实例“给表增加一个索引 Schema 变更”来介绍。 

    •    源数据库版本 12.1.0.2.0
    •    目标测试系统 12.1.0.2.0
    •    系统变更是给 t1 表增加一个索引 
    •    性能报告将生成 HTML 格式的详细信息

    SPA – 使用 PL/SQL API 的简单介绍

    注:DBMS_SQLPA 包及其用法的更多信息,请参考:  Using DBMS_SQLPA

    1.    捕获 SQL 工作负载到一个 SQL 调优集

    创建和填充 STS

    BEGIN 
      DBMS_SQLTUNE.DROP_SQLSET (sqlset_name  => 'MYSIMPLESTSUSINGAPI'); 
    END;
    /

    BEGIN 
      DBMS_SQLTUNE.CREATE_SQLSET (sqlset_name  => 'MYSIMPLESTSUSINGAPI', description  => 'My Simple STS Using the API' );
    END;
    /

    1a. 使用 SCOTT 用户运行一下 PLSQL 代码执行 SQL 语句。(PLSQL 用来模拟使用绑定变量的 SQL 语句工作负载) 
    var b1 number;

    declare
    v_num number;
     begin
      for i in 1..10000 loop
      :b1 := i;
      select c1 into v_num from t1 where c1 = :b1;
     end loop;
    end;
    /

    1b. 从游标缓存中找到使用 parsing schema=SCOTT 的语句来填充 STS

    DECLARE
      c_sqlarea_cursor DBMS_SQLTUNE.SQLSET_CURSOR;
    BEGIN
     OPEN c_sqlarea_cursor FOR SELECT VALUE(p) FROM TABLE(DBMS_SQLTUNE.SELECT_CURSOR_CACHE('parsing_schema_name = ''SCOTT''', NULL, NULL, NULL, NULL, 1, NULL,'ALL')) p;
     DBMS_SQLTUNE.LOAD_SQLSET (sqlset_name => 'MYSIMPLESTSUSINGAPI', populate_cursor => c_sqlarea_cursor);
    END;
    /

    1c. 检查 STS 中捕获了多少 SQL 语句

    COLUMN NAME FORMAT a20
    COLUMN COUNT FORMAT 99999
    COLUMN DESCRIPTION FORMAT a30

    SELECT NAME, STATEMENT_COUNT AS "SQLCNT", DESCRIPTION FROM   USER_SQLSET;

    Results:

    NAME                     SQLCNT DESCRIPTION
    -------------------- ---------- ------------------------------
    MYSIMPLESTSUSINGAPI          12 My Simple STS Using the API

    1d. 显示 STS 的内容

    COLUMN SQL_TEXT FORMAT a30   
    COLUMN SCH FORMAT a3
    COLUMN ELAPSED FORMAT 999999999

    SELECT SQL_ID, PARSING_SCHEMA_NAME AS "SCOTT", SQL_TEXT,   ELAPSED_TIME AS "ELAPSED", BUFFER_GETS FROM   TABLE( DBMS_SQLTUNE.SELECT_SQLSET( 'MYSIMPLESTSUSINGAPI' ) );

    Results: (partial)

    SQL_ID        SCOTT                          SQL_TEXT                                               ELAPSED                  BUFFER_GETS
    ------------- ------------------------------ ------------------------------                                  ----------                     -----------
    0af4p26041xkv SCOTT                 SELECT C1 FROM T1 WHERE C1 = :  169909252             18185689

    2.  设置目标系统

    为了演示目的,这里将使用 STS 的捕获源作为同样的目标测试系统。 

    3.  创建 SPA 任务

    VARIABLE t_name VARCHAR2(100);
    EXEC :t_name := DBMS_SQLPA.CREATE_ANALYSIS_TASK(sqlset_name => 'MYSIMPLESTSUSINGAPI', task_name => 'MYSPATASKUSINGAPI');
    print t_name

    Results:

    T_NAME
    -----------------
    MYSPATASKUSINGAPI

    4.  创建和执行变更前的 SPA 任务

    EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(task_name => 'MYSPATASKUSINGAPI', execution_type => 'TEST EXECUTE', execution_name => 'MY_BEFORE_CHANGE');


    5.  做出系统变更

    CREATE INDEX t1_idx ON t1 (c1);

    6.  创建和执行变更后的 SPA 任务

    EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(task_name => 'MYSPATASKUSINGAPI', execution_type => 'TEST EXECUTE', execution_name => 'MY_AFTER_CHANGE');

    7.  对比和分析变更前和变更后的性能

    EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(task_name => 'MYSPATASKUSINGAPI', execution_type => 'COMPARE PERFORMANCE', execution_name => 'MY_EXEC_COMPARE', execution_params => dbms_advisor.arglist('comparison_metric', 'elapsed_time'));

    -- Generate the Report

    set long 100000000 longchunksize 100000000 linesize 200 head off feedback off echo off TRIMSPOOL ON TRIM ON
    VAR rep   CLOB;
    EXEC :rep := DBMS_SQLPA.REPORT_ANALYSIS_TASK('MYSPATASKUSINGAPI', 'html', 'typical', 'all');
    SPOOL C:mydirSPA_detailed.html
    PRINT :rep
    SPOOL off


    HTML 格式的报告示例:

    下面是 SPA 报告的一部分截屏。报告由3个部分组成,一个部分涉及到变更前和变更后的任务包括 范围,状态,执行起始时间,错误个数和比较的标准;第二个部分总结部分包括了变更带来的负载影响;第三个部分包括了详细的 SQL 信息,比如 SQLID 以及需要比较的度量,比如对负载的影响,执行的频率,以及在这个例子里在变更前后的执行时间这个度量。比如对于 SQL ID 0af4p26041xkv 来说,负载影响是97%。我们要实施的变更对于性能有好的影响,可以把执行时间从12766降低到29。我们还可以看到执行计划在变更后发生了变化。这些信息可以帮助 DBA 进一步关注在特定的问题或者性能退化上,对于当前的这个例子,影响是对性能有提升。

    Image


    下面的截屏显示了在增加了索引后执行计划的变化。这部分信息可以让 DBA 进一步关注在变更前后某个具体 SQL 的执行计划上。对任何 SQL 退化来说,这可以让 DBA 来清楚了解执行计划是如何变化的,并且可以进一步采取计划,比如使用 SQL Tuning Advisor 或者创建 SPM 基线。

    Image

    关于 Real Application Testing 的推荐资源清单:

    •    Oracle Real Application Testing Product Information
    •    Master Note for Real Application Testing Option (Doc ID 1464274.1)
    •    Database Testing: Best Practices (Doc ID 1535885.1)
    •    Mandatory Patches for Database Testing Functionality for Current and Earlier Releases (Doc ID 560977.1)

     ##### sample 0

    注意事项:

    SPA 数据存在2个数据完全一致的库,如果是生产库和测试库不一致,则没有比较意义,因为数据不一致:
    同时测试库需要准备2个环境,一个是类生产库,一个类新库

    section 1:

    1 恢复平台 搭建10g性能测试环境 在恢复平台恢复出10g的生产库,作为性能测试环境,参数保持和生产库一致
    2 11g性能测试库 搭建11g性能测试环境 在linux主机进行跨平台迁移,搭建11g性能测试环境
    3.生产环境 抓取sqlset "在生产环境执行附件sql,对生产性能影响不大。
    抓取持续一周。如果有异常,可以立即停掉。"

    ---------------------------------------------------
    --Step1: 创建名称为STS_SQLSET的SQL_SET.
    ---------------------------------------------------


    BEGIN
    DBMS_SQLTUNE.DROP_SQLSET(
    sqlset_name => 'STS_SQLSET'
    );
    END;
    /


    BEGIN
    DBMS_SQLTUNE.CREATE_SQLSET(SQLSET_NAME => 'STS_SQLSET',
    DESCRIPTION => 'COMPLETE APPLICATION WORKLOAD',
    SQLSET_OWNER =>'DBMGR');
    END;
    /

    ---------------------------------------------------
    --Step2: 初始加载当前数据库中的SQL.
    ---------------------------------------------------

    DECLARE
    STSCUR DBMS_SQLTUNE.SQLSET_CURSOR;
    BEGIN
    OPEN STSCUR FOR
    SELECT VALUE(P)
    FROM TABLE(DBMS_SQLTUNE.SELECT_CURSOR_CACHE('PARSING_SCHEMA_NAME NOT IN (''SYS'', ''SYSTEM'', ''OUTLN'', ''DBSNMP'', ''WMSYS'', ''CTXSYS'', ''XDB'', ''MDSYS'',
    ''ORDPLUGINS'', ''ORDSYS'', ''OLAPSYS'', ''HR'', ''OE'', ''SCOTT'', ''QS_CB'', ''QS_CBADM'', ''QS_ES'', ''QS_OS'', ''QS_CS'', ''QS'', ''QS_ADM'', ''QS_WS'', ''DIP'', ''TSMSYS'', ''EXFSYS'',
    ''LBACSYS'', ''TRACESVR'', ''AURORA$JIS$UTILITY$'', ''OSE$HTTP$ADMIN'', ''DBMGR'', ''OVSEE'', ''DBMONOPR'')
    AND PLAN_HASH_VALUE <> 0 AND UPPER(SQL_TEXT) NOT LIKE ''%TABLE_NAME%''',
    NULL, NULL, NULL, NULL, 1, NULL,
    'ALL')) P;
    -- POPULATE THE SQLSET
    DBMS_SQLTUNE.LOAD_SQLSET(SQLSET_NAME => 'STS_SQLSET',
    POPULATE_CURSOR => STSCUR,
    COMMIT_ROWS => 100,
    SQLSET_OWNER => 'DBMGR');
    CLOSE STSCUR;
    COMMIT;
    EXCEPTION
    WHEN OTHERS THEN
    RAISE;
    END;

    /

    select owner,name,STATEMENT_COUNT from dba_sqlset;

    --观察下初始化收集数据,如果数据太大,可以停下进程
    ---------------------------------------------------
    --Step3: 增量抓取数据库中的SQL, 会连续抓取7天,每小时抓取一次,Sessions一直持续7天. 这一步用shell脚本在后台执行。或者在sqlplus 上执行,如果不会被kiill 到。


    BEGIN
    DBMS_SQLTUNE.CAPTURE_CURSOR_CACHE_SQLSET(SQLSET_NAME => 'STS_SQLSET',
    TIME_LIMIT => 345600,
    REPEAT_INTERVAL => 3600,
    CAPTURE_OPTION => 'MERGE',
    CAPTURE_MODE => DBMS_SQLTUNE.MODE_ACCUMULATE_STATS,
    BASIC_FILTER => 'PARSING_SCHEMA_NAME NOT IN (''SYS'', ''SYSTEM'', ''OUTLN'', ''DBSNMP'', ''WMSYS'', ''CTXSYS'', ''XDB'', ''MDSYS'',
    ''ORDPLUGINS'', ''ORDSYS'', ''OLAPSYS'', ''HR'', ''OE'', ''SCOTT'', ''QS_CB'', ''QS_CBADM'', ''QS_ES'', ''QS_OS'', ''QS_CS'', ''QS'', ''QS_ADM'', ''QS_WS'', ''DIP'', ''TSMSYS'', ''EXFSYS'',''LBACSYS'', ''TRACESVR'', ''AURORA$JIS$UTILITY$'', ''OSE$HTTP$ADMIN'', ''DBMGR'', ''OVSEE'', ''DBMONOPR'')
    AND PLAN_HASH_VALUE <> 0 AND UPPER(SQL_TEXT) NOT LIKE ''%TABLE_NAME%''',
    SQLSET_OWNER => 'DBMGR');
    END;
    /

    --for script runnign in background ,collct from 8/2 to 8/6, 4days totoal

    cd /db/cps/app/opcps/dba

    vi collect_spq.sh

    sqlplus / as sysdba <<eof
    select instance_name from v$instance;
    BEGIN
    DBMS_SQLTUNE.CAPTURE_CURSOR_CACHE_SQLSET(SQLSET_NAME => 'STS_SQLSET',
    TIME_LIMIT => 345600,
    REPEAT_INTERVAL => 3600,
    CAPTURE_OPTION => 'MERGE',
    CAPTURE_MODE => DBMS_SQLTUNE.MODE_ACCUMULATE_STATS,
    BASIC_FILTER => 'PARSING_SCHEMA_NAME NOT IN (''SYS'', ''SYSTEM'', ''OUTLN'', ''DBSNMP'', ''WMSYS'', ''CTXSYS'', ''XDB'', ''MDSYS'',
    ''ORDPLUGINS'', ''ORDSYS'', ''OLAPSYS'', ''HR'', ''OE'', ''SCOTT'', ''QS_CB'', ''QS_CBADM'', ''QS_ES'', ''QS_OS'', ''QS_CS'', ''QS'', ''QS_ADM'', ''QS_WS'', ''DIP'', ''TSMSYS'', ''EXFSYS'',''LBACSYS'', ''TRACESVR'', ''AURORA$JIS$UTILITY$'', ''OSE$HTTP$ADMIN'', ''DBMGR'', ''OVSEE'', ''DBMONOPR'')
    AND PLAN_HASH_VALUE <> 0 AND UPPER(SQL_TEXT) NOT LIKE ''%TABLE_NAME%''',
    SQLSET_OWNER => 'DBMGR');
    END;
    /
    eof


    4 生产环境 "第三步完成后,
    创建中间表,将sqlset打包到中间表" "exec dbms_sqltune.create_stgtab_sqlset(table_name => 'STS_STBTAB' ,schema_name => 'DBMGR');
    exec dbms_sqltune.pack_stgtab_sqlset(sqlset_name =>'STS_SQLSET' ,sqlset_owner =>'DBMGR' ,staging_table_name =>'STS_STBTAB' ,staging_schema_owner => 'DBMGR' );"

    方法1: 

    (

    转换成中转表之后,我们可以再做一次去除重复的操作。当然,你也可以根据module来删除一些不必要的游标。

    delete from SPA.SQLSET_TAB a where rowid !=(select max(rowid) from SQLSET_TAB b where a.FORCE_MATCHING_SIGNATURE=b.FORCE_MATCHING_SIGNATURE and a.FORCE_MATCHING_SIGNATURE<>0);
    
    delete from SPA.SQLSET_TAB where MODULE='PL/SQL Developer';

    )

    方法2:

    (

    exec dbms_sqltune.create_stgtab_sqlset(table_name => 'STS_STBTAB_08' ,schema_name => 'DBMGR');
    exec dbms_sqltune.pack_stgtab_sqlset(sqlset_name =>'STS_SQLSET' ,sqlset_owner =>'DBMGR' ,staging_table_name =>'STS_STBTAB_08' ,staging_schema_owner => 'DBMGR' );




    create table sts_b as select distinct(to_char(s.force_matching_signature)) b from DBMGR.STS_STBTAB_08 s;

    create index sts_b_1_force on STS_STBTAB_08(to_char(force_matching_signature));

    DECLARE
    T VARCHAR2(50);
    cursor STSCUR IS select b from sts_b;
    STSCUR_1 STS_STBTAB_08%ROWTYPE;
    BEGIN
    OPEN STSCUR;
    LOOP
    fetch STSCUR into T;
    EXIT WHEN STSCUR%NOTFOUND;
    -- DBMS_OUTPUT.PUT_LINE(T);
    select * into STSCUR_1 from ( (select * from STS_STBTAB_08 st where (to_char(st.force_matching_signature)) =T ) order by cpu_time desc) where rownum < 2;
    delete STS_STBTAB_08 where (to_char(force_matching_signature)) =T;
    insert into STS_STBTAB_08 values STSCUR_1;
    commit;
    -- DBMS_OUTPUT.PUT_LINE(STSCUR_1.SQL_ID);
    END LOOP;
    CLOSE STSCUR;
    END;

    )

    5 生产环境 导出sqlset "expdp导出DBMGR.STS_STBTAB


    select count(*) from DBMGR.STS_STBTAB;


    exp dbmgr/db1234DBA tables=STS_STBTAB file=/db/cps/archivelog/exp_SQLSET_TAB.dmp log=/db/cps/archivelog/exp_SQLSET_TAB.log FEEDBACK=1000 BUFFER=5000000
    "

    section 2:

    将sqlset导入11g性能测试库

    6 11g性能测试库 导入到11g性能测试库 impdp导入DBMGR.STS_STBTAB",

    因为有70万条数据,跑得时间非常慢,考虑先过滤信息,在跑,主要过滤方法是排除文字常量一样的SQL,然后取其中最大buffer get 的一条记录,最后的sql_id 和记录放在sts_b_2 表里。最终记录在2万条左右,方法如下:


    drop table sts_b;
    drop table sts_b_1;
    drop table sts_b_2;
    drop table sts_b_3;

    create table sts_b as select distinct(to_char(s.force_matching_signature)) b from dba_sqlset_statements s;
    create table sts_b_1 as select * from dba_sqlset_statements;
    create index sts_b_1_force on sts_b_1(to_char(force_matching_signature));
    create table sts_b_2 (sql_id varchar2(50));
    create table sts_b_3 as select * from dba_sqlset_statements;

    DECLARE
    T VARCHAR2(50);
    cursor STSCUR IS select b from sts_b;
    STSCUR_1 dba_sqlset_statements%ROWTYPE;
    BEGIN
    OPEN STSCUR;
    LOOP
    fetch STSCUR into T;
    EXIT WHEN STSCUR%NOTFOUND;
    -- DBMS_OUTPUT.PUT_LINE(T);
    select * into STSCUR_1 from ( (select * from sts_b_1 st where (to_char(st.force_matching_signature)) =T ) order by cpu_time desc) where rownum < 2;
    delete sts_b_1 where (to_char(force_matching_signature)) =T;
    insert into sts_b_2 values(STSCUR_1.SQL_ID);
    commit;
    -- DBMS_OUTPUT.PUT_LINE(STSCUR_1.SQL_ID);
    END LOOP;
    CLOSE STSCUR;
    END;


    --select * into STSCUR_1 from ( (select * from dba_sqlset_statements st where (to_char(st.force_matching_signature)) =6018318222786944325 ) order by cpu_time ---desc) where rownum < 2;

    7 11g性能测试库 sqlset解包 exec dbms_sqltune.unpack_stgtab_sqlset(sqlset_name => 'STS_SQLSET',sqlset_owner => 'DBMGR' ,replace => True,staging_table_name =>'STS_STBTAB' ,staging_schema_owner => 'DBMGR');



    section 3:
    将sqlset导入10g测试库

    8 10g测试环境 授权 "grant all on spa_sqlpa to dbmgr;
    grant all on dbms_sqlpa to dbmgr;
    "
    9 10g测试环境 导出导入 "impdp导入DBMGR.STS_STBTAB


    imp dbmgr/dbmgr fromuser=dbmgr touser=dbmgr file=/oraclelv/exp_SQLSET_TAB.dmp feedback=1000 log=/oraclelv/imp_SQLSET_TAB.log BUFFER=5000000


    imp dbmgr/db1234DBA fromuser=dbmgr touser=dbmgr file=/datalv03/afa/exp_SQLSET_TAB.dmp feedback=1000 log=/datalv03/afa/imp_SQLSET_TAB.log BUFFER=5000000
    "
    10 10g测试环境 解包sqlset exec dbms_sqltune.unpack_stgtab_sqlset(sqlset_name => 'STS_SQLSET',sqlset_owner => 'DBMGR' ,replace => True,staging_table_name =>'STS_STBTAB' ,staging_schema_owner => 'DBMGR');
    11 11g性能测试库 创建DBLINK "create public database link to_10g connect to dbmgr identified by xxxxx using 'xxxxxxx'


    create public database link to_10g connect to dbmgr identified by db1234DBA
    using ' (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST =25.10.0.199)(PORT = 1539)) (CONNECT_DATA =(sid = afa)))';"


    section 4:
    第一次执行spa回放,获得10g性能测试环境的数据

    12 11性能测试库 创建task "declare
    mytask varchar2(100);
    begin
    mytask := dbms_sqlpa.create_analysis_task(sqlset_name => 'STS_SQLSET',sqlset_owner => 'DBMGR',task_name => 'TASK_10G');
    END;
    /
    "
    13 11g性能测试库 生成第一次执行task的脚本,通过DATABASE_LINK to_10g 远程执行"
    vi spa_10g.sh
    sqlplus -S /nolog <<SQLEnd
    conn / as sysdba
    exec DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(task_name=>'TASK_10G',execution_type=>'test execute',execution_name=>'spa10g',execution_params =>dbms_advisor.argList('DATABASE_LINK','TO_10G','EXECUTE_COUNT',5) ,execution_desc => 'before_change');
    exit
    SQLEnd" "可以看到SPA_DIR下有BEF_TASK_SQLSET_NO_i.sh脚本,
    "
    14 11g性能测试库 "执行task,
    执行第一次spa回放" "nohup sh spa_10g.sh > spa_10g.log &
    " 发起目标库执行第一次spa回放
    15 11g性能测试库 查询回放进度 "SELECT owner,task_name,execution_name,a.execution_type,execution_start,execution_last_modified,execution_end,status,b.SOFAR,b.START_TIME,b.LAST_UPDATE_TIME
    from dba_advisor_executions a, v$advisor_progress b where a.execution_name like 'spa10g%';" 计算 2万笔 笔数据需要多久完成,


    section 5:
    第二次执行spa回放,获得11g性能测试环境的数据

    16 11g性能测试库 创建task "declare
    mytask varchar2(100);
    begin
    mytask := dbms_sqlpa.create_analysis_task(sqlset_name => 'STS_SQLSET',sqlset_owner => 'DBMGR',task_name => 'TASK_11G');
    END;
    /
    "
    17 11g性能测试库 生成第二次执行task的脚本 "vi spa_11g.sh
    sqlplus -S /nolog <<SQLEnd
    conn / as sysdba
    exec DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(task_name=>'TASK_11G',execution_type=>'test execute',execution_name=>'spa11g_1',execution_params =>dbms_advisor.argList('EXECUTE_COUNT',5) ,execution_desc => 'after_change');
    exit
    SQLEnd" 可以看到SPA_DIR下有AFT_TASK_SQLSET_NO_i.sh脚本
    18 11g性能测试库 "执行task,
    执行第二次spa回放" "nohup sh spa_11g.sh > spa_11g.log &
    " 发起目标库执行第二次spa回放,5个小时左右
    19 11g性能测试库 查询回放进度 "SELECT owner,task_name,execution_name,a.execution_type,execution_start,execution_last_modified,execution_end,status,b.SOFAR,b.START_TIME,b.LAST_UPDATE_TIME
    from dba_advisor_executions a, v$advisor_progress b where a.execution_name like 'spa11g%';"

    section 6:
    20 11g性能测试库 取出buffer gets变大的sql进行分析

    20.1.分析SQL 如下
    Select *
    From (Select b.*, dbms_lob.substr(st.sql_text, 3400) sql_text
    From SYS.Wrh$_Sqltext st,
    (Select task_name,
    sql_id,
    executions,
    detal_buffer_gets,
    bf_buffer_gets,
    af_buffer_gets,
    bf_plan_hash_value,
    bf_rows_processed,
    af_plan_hash_value,
    af_ROWS_PROCESSED
    From (Select task_name,
    sql_id,
    bf_executions executions,
    round(af_buffer_gets / af_EXECUTIONS) -
    round(bf_buffer_gets / bf_executions) detal_buffer_gets,
    round(bf_buffer_gets / bf_executions) bf_buffer_gets,
    round(af_buffer_gets / af_EXECUTIONS) af_buffer_gets,
    bf_plan_hash_value,
    bf_rows_processed / bf_executions bf_rows_processed,
    af_plan_hash_value,
    af_ROWS_PROCESSED / af_EXECUTIONS af_ROWS_PROCESSED
    From (Select bf.task_name,
    bf.sql_id,
    bf.executions bf_executions,
    bf.plan_hash_value bf_plan_hash_value,
    bf.buffer_gets bf_buffer_gets,
    bf.rows_processed bf_rows_processed,
    af.plan_hash_value af_plan_hash_value,
    af.buffer_gets af_buffer_gets,
    af.executions af_executions,
    af.rows_processed af_rows_processed
    From dba_advisor_sqlstats af,
    dba_advisor_sqlstats bf
    Where af.execution_name='SPA11G'
    And af.task_name like '%TASK_11G%'
    And bf.task_name like '%TASK_10G%'
    And bf.execution_name='SPA10G'
    And bf.sql_id = af.sql_id))
    Where detal_buffer_gets > 0) b
    Where st.sql_id = b.sql_id
    Order By detal_buffer_gets Desc)
    Where sql_text Not Like '%Analyze(%'
    And sql_text Not Like '%SELECT /* DS_SVC */%'
    And sql_text Not Like '%/* OPT_DYN_SAMP */%';

    Select *
    From (Select b.*, dbms_lob.substr(st.sql_text, 3400) sql_text
    From SYS.Wrh$_Sqltext st,
    (Select task_name,
    sql_id,
    executions,
    detal_buffer_gets,
    bf_buffer_gets,
    af_buffer_gets,
    bf_plan_hash_value,
    bf_rows_processed,
    af_plan_hash_value,
    af_ROWS_PROCESSED
    From (Select task_name,
    sql_id,
    bf_executions executions,
    round(af_buffer_gets / af_EXECUTIONS) -
    round(bf_buffer_gets / bf_executions) detal_buffer_gets,
    round(bf_buffer_gets / bf_executions) bf_buffer_gets,
    round(af_buffer_gets / af_EXECUTIONS) af_buffer_gets,
    bf_plan_hash_value,
    bf_rows_processed / bf_executions bf_rows_processed,
    af_plan_hash_value,
    af_ROWS_PROCESSED / af_EXECUTIONS af_ROWS_PROCESSED
    From (Select bf.task_name,
    bf.sql_id,
    bf.executions bf_executions,
    bf.plan_hash_value bf_plan_hash_value,
    bf.buffer_gets bf_buffer_gets,
    bf.rows_processed bf_rows_processed,
    af.plan_hash_value af_plan_hash_value,
    af.buffer_gets af_buffer_gets,
    af.executions af_executions,
    af.rows_processed af_rows_processed
    From dba_advisor_sqlstats af,
    dba_advisor_sqlstats bf
    Where af.execution_name='spa11g_1'
    And af.task_name like '%TASK_11G%'
    And bf.task_name like '%TASK_10G%'
    And bf.execution_name='spa10g'
    And bf.sql_id = af.sql_id))
    Where detal_buffer_gets > 0) b
    Where st.sql_id = b.sql_id
    Order By detal_buffer_gets Desc)
    Where sql_text Not Like '%Analyze(%'
    And sql_text Not Like '%SELECT /* DS_SVC */%'
    And sql_text Not Like '%/* OPT_DYN_SAMP */%';


    20.2." 1.最后检查的结果SQL大于10%的有将近400多条。在过滤一遍buffer_get 大于1000以上的,只有30多条,因此重点分析这30条sql数据。
    2.把这30条SQL依次放在PL/SQL developer里格式化后,在放入同一个文件,按照sql_id 编好号。"

    20.3."1.如果spa数据过多,每次都要查询很久的话 ,可以考虑创建临时表 a,加快查询速度 。
    create table a as
    (
    Select *
    From (Select b.*, dbms_lob.substr(st.sql_text, 3400) sql_text
    From SYS.Wrh$_Sqltext st,
    (Select task_name,
    sql_id,
    executions,
    detal_buffer_gets,
    bf_buffer_gets,
    af_buffer_gets,
    bf_plan_hash_value,
    bf_rows_processed,
    af_plan_hash_value,
    af_ROWS_PROCESSED
    From (Select task_name,
    sql_id,
    bf_executions executions,
    round(af_buffer_gets / af_EXECUTIONS) -
    round(bf_buffer_gets / bf_executions) detal_buffer_gets,
    round(bf_buffer_gets / bf_executions) bf_buffer_gets,
    round(af_buffer_gets / af_EXECUTIONS) af_buffer_gets,
    bf_plan_hash_value,
    bf_rows_processed / bf_executions bf_rows_processed,
    af_plan_hash_value,
    af_ROWS_PROCESSED / af_EXECUTIONS af_ROWS_PROCESSED
    From (Select bf.task_name,
    bf.sql_id,
    bf.executions bf_executions,
    bf.plan_hash_value bf_plan_hash_value,
    bf.buffer_gets bf_buffer_gets,
    bf.rows_processed bf_rows_processed,
    af.plan_hash_value af_plan_hash_value,
    af.buffer_gets af_buffer_gets,
    af.executions af_executions,
    af.rows_processed af_rows_processed
    From dba_advisor_sqlstats af,
    dba_advisor_sqlstats bf
    Where af.execution_name='spa11g_1'
    And af.task_name like '%TASK_11G%'
    And bf.task_name like '%TASK_10G%'
    And bf.execution_name='spa10g'
    And bf.sql_id = af.sql_id))
    Where detal_buffer_gets > 0) b
    Where st.sql_id = b.sql_id
    Order By detal_buffer_gets Desc)
    Where sql_text Not Like '%Analyze(%'
    And sql_text Not Like '%SELECT /* DS_SVC */%'
    And sql_text Not Like '%/* OPT_DYN_SAMP */%');" "

    2.如下是从a表中找到升级前后变化量大于10%的SQL,detal_buffer_gets这个变量就是变化量.

    select sql_id,sql_text,bf_buffer_gets,af_buffer_gets,(detal_buffer_gets/bf_buffer_gets *100) change from a where detal_buffer_gets/bf_buffer_gets *100 > 10;
    "

    21 11g性能测试库 plan改变的sql

    Select st.sql_id,
    sst.executions,
    dbms_lob.substr(st.sql_text, 3000) sql_text
    From sys.wrh$_sqltext st,
    dba_sqlset_statements sst,
    (Select Distinct sql_id
    From (Select sql_id,
    operation,
    options,
    object_name,
    object_alias,
    object_type,
    Id,
    parent_id,
    depth
    From dba_advisor_sqlplans af
    Where af.task_name = 'TASK_11G' And af.execution_name = 'SPA11G'
    Minus
    Select sql_id,
    operation,
    options,
    object_name,
    object_alias,
    object_type,
    Id,
    parent_id,
    depth
    From dba_advisor_sqlplans bf
    Where bf.task_name = 'TASK_10G' And bf.execution_name = 'SPA10G'
    )) cp
    Where st.sql_id = cp.sql_id
    And sst.sql_id = cp.sql_id
    And st.sql_text Not Like '%Analyze(%'
    And st.sql_text Not Like '%SELECT /* DS_SVC */%'
    And st.sql_text Not Like '%/* OPT_DYN_SAMP */%'
    And sst.sqlset_name Like 'STS_SQLSETNO%'
    ;

    Select st.sql_id,
    sst.executions,
    dbms_lob.substr(st.sql_text, 3000) sql_text
    From sys.wrh$_sqltext st,
    dba_sqlset_statements sst,
    (Select Distinct sql_id
    From (Select sql_id,
    operation,
    options,
    object_name,
    object_alias,
    object_type,
    Id,
    parent_id,
    depth
    From dba_advisor_sqlplans af
    Where af.task_name = 'TASK_11G' And af.execution_name = 'spa11g_1'
    Minus
    Select sql_id,
    operation,
    options,
    object_name,
    object_alias,
    object_type,
    Id,
    parent_id,
    depth
    From dba_advisor_sqlplans bf
    Where bf.task_name = 'TASK_10G' And bf.execution_name = 'spa10g'
    )) cp
    Where st.sql_id = cp.sql_id
    And sst.sql_id = cp.sql_id
    And st.sql_text Not Like '%Analyze(%'
    And st.sql_text Not Like '%SELECT /* DS_SVC */%'
    And st.sql_text Not Like '%/* OPT_DYN_SAMP */%'
    And sst.sqlset_name Like '%STS_SQLSET%'


    22 11g性能测试库 "生成任务task_11g的报告,
    生成任务task_10g的报告" "conn / as sysdba
    1.SQL> SET LONG 999999 longchunksize 100000 linesize 200 head off feedback off echo off
    SQL> spool task01_before_change.html
    SQL> SELECT DBMS_SQLPA.REPORT_ANALYSIS_TASK('TASK_11G', 'HTML', 'ALL', 'ALL') FROM dual;
    SQL>spoo off

    SQL>alter session set events '31156 trace name context forever,level 0x400';
    SQL> spool task01_after_change.html
    SQL> SELECT DBMS_SQLPA.REPORT_ANALYSIS_TASK('TASK_10G', 'HTML', 'ALL', 'ALL') FROM dual;
    SQL>spoo off"


    23.
    23 11g性能测试库 分析性能变差的sql突然变化的原因以及对应SQL优化。"分析性能突然变差的SQL原因周期比较长。
    主要可以通过SQLT报告来分析。,这里主要是对性能变化的SQL的调优。" 新生成的SQL_PROFILE可以通过导入和导出方式迁移到新库,这样可以实现优化SQL的目的

    --手工调优SQL方法,在11g 数据库里,根据SQL_ID,然后根据SQL_ID绑定profile

    DECLARE
    my_task_name VARCHAR2(30);
    my_sqltext CLOB;
    BEGIN
    select dbms_lob.substr(sql_fulltext,4000) sql_text from v$sqlarea where sql_id='cybxr1trru31n';
    my_task_name := DBMS_SQLTUNE.CREATE_TUNING_TASK(
    sql_text=> my_sqltext,
    user_name => 'AFA',
    scope => 'COMPREHENSIVE',
    time_limit => 60,
    task_name => 'my_sql_tuning_task_test1',
    description => 'Task to tune a query on a specified table');
    END;
    /

    exec DBMS_SQLTUNE.EXECUTE_TUNING_TASK( task_name => 'my_sql_tuning_task_test1');

    set long 2000
    SELECT DBMS_SQLTUNE.REPORT_TUNING_TASK( 'my_sql_tuning_task_test1') from DUAL;


    --自动调优方法:思路如下,手工执行SQL,得到SQL_ID,再调用自动分析方法DBMS_SQLTUNE分析,最后得到分析结果以及建议,最后将结果建议实施。

    ## 自动调优开始begin
    rm t.log
    sqlplus afa/afa <<eof
    spool t.log

    SELECT *
    FROM (SELECT agentserialno,
    FROM v_beps_returnticketinfo
    WHERE brno = '756045'
    AND workdate >= '20180701'
    ORDER BY workdate desc, agentserialno desc))
    WHERE RN <= 15
    AND RN BETWEEN 1 AND 15
    /

    select * from table(dbms_xplan.display_cursor());

    spool off
    eof


    sql_id=`grep SQL_ID t.log|awk '{print $2}'|awk -F, '{print $1}'`


    sqlplus / as sysdba <<eof1
    set pagesize 0 linesize 300
    select * from dual;
    exec DBMS_SQLTUNE.DROP_TUNING_TASK(task_name => 'my_sql_tuning_task_test1');
    select * from dual;
    DECLARE
    my_task_name VARCHAR2(30);
    my_sqltext CLOB;
    BEGIN
    select dbms_lob.substr(sql_fulltext,4000) sql_text into my_sqltext from v$sqlarea where sql_id='$sql_id';
    my_task_name := DBMS_SQLTUNE.CREATE_TUNING_TASK(
    sql_text=> my_sqltext,
    user_name => 'AFA',
    scope => 'COMPREHENSIVE',
    time_limit => 1600,
    task_name => 'my_sql_tuning_task_test1',
    description => 'Task to tune a query on a specified table');
    END;
    /
    exec DBMS_SQLTUNE.EXECUTE_TUNING_TASK( task_name => 'my_sql_tuning_task_test1');
    /
    set long 200000
    SELECT DBMS_SQLTUNE.REPORT_TUNING_TASK( 'my_sql_tuning_task_test1') from DUAL;
    execute dbms_sqltune.accept_sql_profile(task_name => 'my_sql_tuning_task_test1', task_owner => 'SYS', replace => TRUE,force_match=>true);
    /
    eof1

    ####自动调优结束


    附录:分析sql变慢的原因,需要使用SQLT 中xplore, 方法如下:

    Method 3)如何找到是优化器的哪个变化导致SQL性能变化 ,如果数据库升级,比如从10g升级到11g,sql 运行缓慢,可以使用如下方法

    单独安装sqlt->utl->xplore目录下执行install.sql
    生成create_xplore_script.sql并执行
    修改sql语句,增加hint /* ^^unique_id */保存到文件
    选择XECUTE模式执行
    选择CBO Parameters Y
    选择EXADATA Parameters N
    选择Fix Control Y
    选择SQL Monitor N
    执行@xplore_script_1.sql带入变量用户、密码、sql文件名
    分析生成的html格式报告


    ##sample
    上传SQLT,解压缩SQLT, 不需要安装SQLT ,直接按照如下方法实施

    cd sqlt/utl/xplore

    Install:
    ~~~~~~~
    1. Connect as SYS and execute install script:

    # sqlplus / as sysdba
    SQL> START install.sql


    Installation completed.
    You are now connected as afa.

    1. Set CBO env if needed
    2. Execute @create_xplore_script.sql
    --


    2. Generate the xplore_script in the same session within which you executed step one.


    cd /home/oracle/sqlt/sqlt/utl/xplore

    改写sql create_xplore_script.sql ,思路如下,去掉ACC这一行,增加define 这一行。

    --#ACC xplore_method PROMPT 'Enter "XPLORE Method" [XECUTE]: ';
    define xplore_method="XECUTE"
    PRO Parameter 2:
    PRO Include CBO Parameters: Y (default) or N
    --ACC include_cbo_parameters PROMPT 'Enter "CBO Parameters" [Y]: ';
    define include_cbo_parameters="Y"
    PRO
    PRO Parameter 3:
    PRO Include Exadata Parameters: Y (default) or N
    --ACC include_exadata_parameters PROMPT 'Enter "EXADATA Parameters" [Y]: ';
    define include_exadata_parameters="N"
    PRO
    PRO Parameter 4:
    PRO Include Fix Control: Y (default) or N
    --ACC include_fix_control PROMPT 'Enter "Fix Control" [Y]: ';
    define include_fix_control="Y"
    PRO
    PRO Parameter 5:
    PRO Generate SQL Monitor Reports: N (default) or Y
    PRO Only applicable when XPLORE Method is XECUTE
    --ACC generate_sql_monitor_reports PROMPT 'Enter "SQL Monitor" [N]: ';
    define generate_sql_monitor_reports="Y"


    SQL> conn app/passwd
    sqlplus afa/afa <<eof
    @create_xplore_script.sql
    eof

    3. Execute generated xplore_script. It will ask for two parameters:
    修改sql语句,增加hint /* ^^unique_id */保存到文件

    conn app/passwd

    @xplore_script_1.sql带入变量用户、密码、sql文件名


    P1. Name of the script to be executed. 一定要加入/* ^^unique_id */ 这个关键字,即可,最后结果会生成zip文件

    Notes:
    Example:
    SELECT /* ^^unique_id */ t1.col1, etc.

    P2. Password for <user>

    4. After you are done using XPLORE you may want to bounce the
    database since it executed some ALTER SYSTEM commands:
    (when meet erro ERROR at line 1:ORA-01422: exact fetch returns more than requested number of rows, need start db)

    # sqlplus / as sysdba
    SQL> shutdown immediate
    SQL> startup


    Uninstall:
    ~~~~~~~~~
    1. Connect as SYS and execute uninstall script:

    # sqlplus <user>
    SQL> START uninstall.sql

    Note:
    You will be asked for the test case user.

    ##### sample 1

    作为 Oracle Real Application Testing 选件/特性,这篇文章将提供一个关于 SQL 性能分析器(SPA)工具的简要概览。这是此系列的第一部分。第二部分于下个月继续讲述数据库捕获和重演。关于 SPA 的详细信息可参考:

    数据库测试指南

    DBA 的一个重要工作是确保在一个计划内的变更安排后,当前生产环境负载和 SQL 执行计划可以持续平滑运行。变更可能包含数据库升级、增加一个新索引或改变一个特定的数据库参数。 SPA 工具作为 Oracle Real Application Testing 选件的一部分提供,允许将生产环境负载中的 SQL 拿到测试环境的目标数据库运行,所以可以通过比对结果识别退化的性能问题,并在迁移、升级或特定系统变更之前修复。如果您计划使用数据库重演特性,在运行重演之前使用 SPA 是 Oracle 建议的最佳实践。目标是在数据库重演之前识别和修复所有的 SQL 性能退化,所以我们可以只关注重演特性中的并发和吞吐量 。SQL 性能分析器使用 SQL 调优集(STS)作为输入,STS 已经存在了很长一段时间了,这允许 DBA 提取现有生产环境的 SQL 语句工作负载并在节省时间和资源的前提下轻松比对一组变更前和变更后的执行结果。 一个 SQL 调优集(STS)是一个包含了一系列从工作负载中得来的 SQL 语句集及其执行上下文信息(例如用户和绑定变量、执行的统计信息和执行计划)的数据库对象。关于 STS 的更多信息,请参考: Managing SQL Tuning Sets

    注: SQL 性能分析器需要 Oracle Real Application Testing 许可. 更多信息,请参考: Oracle Database Licensing Information.

    如下清单提供了一些 DBA 考虑使用 SPA 工具的常见场景。

    使用场景


    1. 数据库升级 – 一个新版本数据库意味着一个新版本的优化器。DBA 能在升级生产系统之前主动发现任何 SQL 性能退化。
    2. 部署一个补丁 – 您可能会部署一个与性能或优化器相关的特定修复的补丁。使用 SPA 来检查您的生产环境 SQL 负载能帮助您验证这个补丁不会引起任何 SQL 性能退化。
    3. 数据库初始化参数变更 - 有各种各样的数据库参数可能影响性能,所以这是 SPA 用处的一个很好的场景。
    4. Schema 变更例如增加索引 – schema 变更和修改,如增加索引会直接影响优化器的决定和计划。SPA 可用来测试这些变更并确保不会引入负面影响。
    5. 改变或刷新优化器统计信息 – 优化器统计信息直接关系到优化器的决策和执行计划的生成,您可以使用 SPA 来测试新的统计信息和设置来确保它们不会引起 SQL 性能退化。

    使用 SPA 包括执行以下工作流文档/步骤。SPA 工具完全集成到 Oracle12c Cloud Control 中,Oracle 也提供了一个名为 DBMS_SQLPA 的 PLSQL 包来允许 DBA 使用 PL/SQL 实施这些步骤。这个工作流使用了一个迭代的过程来执行、对比和分析、以及修复这些退化。DBA 可使用诸如 SQL 执行计划基线或 SQL 调优顾问等工具/特性来修复 SPA 发现的坏或退化的 SQL 语句。

    SPA 工作流
    1. 捕捉您想要分析的生产系统的 SQL 工作负载,并将其保存为一个 SQL 调优集。
    2. 设置目标测试系统(这应该尽可能多地和生产系统一致)。
    3. 在测试系统创建一个 SPA 任务。

    Image

    4. 构建变更前 SPA 任务。
    5. 进行系统变更。
    6. 构建变更后 SPA 任务。
    7. 对比和分析变更前后的性能数据。
    8. 调优或修复任何退化的 SQL 语句。
    9. 重复地6~8步,直到 SQL 性能在测试系统上可接受。

    出于本文的目的,我们将通过一个简单实例10.2.0.4 到11,2,0.4 来介绍。

    • 源数据库版本 10.2.0.4 25.10.0.199
    • 目标测试系统 11.2.0.4 25.10.0.31
    • 性能报告将生成 HTML 格式的详细信息

    SPA – 使用 PL/SQL API 的简单介绍

    注:DBMS_SQLPA 包及其用法的更多信息,请参考: Using DBMS_SQLPA

    1. 捕获 SQL 工作负载到一个 SQL 调优集

    创建和填充 STS

    BEGIN
    DBMS_SQLTUNE.DROP_SQLSET (sqlset_name => 'MYSIMPLESTSUSINGAPI');
    END;
    /

    BEGIN
    DBMS_SQLTUNE.CREATE_SQLSET (sqlset_name => 'MYSIMPLESTSUSINGAPI', description => 'My Simple STS Using the API' );
    END;
    /
    PL/SQL procedure successfully completed.

    2,检查SYSAUX空间是否足够

    09:26:38 sys@LUNAR>@ts

    SELECT a.tablespace_name ,b.maxbytes/1024/1024/1024 "maxbyes_GB",total/1024/1024/1024 "bytes_GB",free/1024/1024/1024 "free_GB",(total-free) /1024/1024/1024 "use_GB",
    ROUND((total-free)/total,4)*100 "use_%",ROUND((total-free)/b.maxbytes,4)*100 "maxuse_%"
    FROM
    (SELECT tablespace_name,SUM(bytes) free FROM DBA_FREE_SPACE
    GROUP BY tablespace_name
    ) a,
    (SELECT tablespace_name,sum(case autoextensible when 'YES' then maxbytes else bytes end) maxbytes,SUM(bytes) total FROM DBA_DATA_FILES
    GROUP BY tablespace_name
    ) b
    WHERE a.tablespace_name=b.tablespace_name
    order by "maxuse_%" desc;


    8 rows selected.

    1a. 使用 SCOTT 用户运行一下 PLSQL 代码执行 SQL 语句。(PLSQL 用来模拟使用绑定变量的 SQL 语句工作负载) 使用swithbech 模拟压力
    ##var b1 number;

    ##declare
    ##v_num number;
    ## begin
    ## for i in 1..10000 loop
    ## :b1 := i;
    ## select c1 into v_num from t1 where c1 = :b1;
    ## end loop;
    ##end;
    ##/

    1b. 从游标缓存中找到使用 parsing schema=SCOTT 的语句来填充 STS

    DECLARE
    c_sqlarea_cursor DBMS_SQLTUNE.SQLSET_CURSOR;
    BEGIN
    OPEN c_sqlarea_cursor FOR SELECT VALUE(p) FROM TABLE(DBMS_SQLTUNE.SELECT_CURSOR_CACHE('parsing_schema_name = ''SOE''', NULL, NULL, NULL, NULL, 1, NULL,'ALL')) p;
    DBMS_SQLTUNE.LOAD_SQLSET (sqlset_name => 'MYSIMPLESTSUSINGAPI', populate_cursor => c_sqlarea_cursor);
    END;
    /

    上述过程一般执行时间比较长,因此,通常放到后台执行。
    这里我们看到加载的SQL明显增加了很多:


    1c. 检查 STS 中捕获了多少 SQL 语句

    COLUMN NAME FORMAT a20
    COLUMN COUNT FORMAT 99999
    COLUMN DESCRIPTION FORMAT a30

    SELECT NAME, STATEMENT_COUNT AS "SQLCNT", DESCRIPTION FROM USER_SQLSET;

    Results:

    NAME SQLCNT DESCRIPTION
    -------------------- ---------- ------------------------------
    MYSIMPLESTSUSINGAPI 12 My Simple STS Using the API

    1d. 显示 STS 的内容

    COLUMN SQL_TEXT FORMAT a30
    COLUMN SCH FORMAT a3
    COLUMN ELAPSED FORMAT 999999999

    SELECT SQL_ID, PARSING_SCHEMA_NAME AS "SCOTT", SQL_TEXT, ELAPSED_TIME AS "ELAPSED", BUFFER_GETS FROM TABLE( DBMS_SQLTUNE.SELECT_SQLSET( 'MYSIMPLESTSUSINGAPI' ) );

    Results: (partial)

    SQL_ID SCOTT SQL_TEXT ELAPSED BUFFER_GETS
    ------------- ------------------------------ ------------------------------ ---------- -----------
    0af4p26041xkv SCOTT SELECT C1 FROM T1 WHERE C1 = : 169909252 18185689

    在源库上执行打包SQL TUNING SET的操作,然后exp/imp到新库上


    exec dbms_sqltune.create_stgtab_sqlset(table_name => 'STS_STBTAB' ,schema_name => 'DBMGR');

    exec dbms_sqltune.pack_stgtab_sqlset(sqlset_name =>'MYSIMPLESTSUSINGAPI' ,sqlset_owner =>'SYS' ,staging_table_name =>'STS_STBTAB' ,staging_schema_owner => 'DBMGR' );

    select count(*) from DBMGR.STS_STBTAB;


    exp dbmgr/db1234DBA tables=STS_STBTAB file=/home/oracle/xtts/bak/exp_SQLSET_TAB.dmp log=/home/oracle/xtts/bak/exp_SQLSET_TAB.log FEEDBACK=1000 BUFFER=5000000


    ####
    Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
    With the Partitioning, OLAP, Data Mining and Real Application Testing options
    Export done in ZHS16GBK character set and UTF8 NCHAR character set

    About to export specified tables via Conventional Path ...
    . . exporting table STS_STBTAB
    61 rows exported
    . . exporting table STS_STBTAB_CBINDS
    0 rows exported
    . . exporting table STS_STBTAB_CPLANS
    260 rows exported
    #####

    2. 设置目标系统

    ###为了演示目的,这里将使用 STS 的捕获源作为同样的目标测试系统。

    imp dbmgr/dbmgr fromuser=dbmgr touser=sys file=/home/oracle/xtts/bak/exp_SQLSET_TAB.dmp feedback=1000 log=/home/oracle/xtts/bak/imp_SQLSET_TAB.log BUFFER=5000000

    Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
    With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
    Data Mining and Real Application Tes

    Export file created by EXPORT:V10.02.01 via conventional path
    import done in ZHS16GBK character set and AL16UTF16 NCHAR character set
    export server uses UTF8 NCHAR character set (possible ncharset conversion)
    . importing DBMGR's objects into DBMGR

    . . importing table "STS_STBTAB"
    61 rows imported
    . . importing table "STS_STBTAB_CBINDS"
    0 rows imported
    . . importing table "STS_STBTAB_CPLANS"
    260 rows imported


    exec dbms_sqltune.unpack_stgtab_sqlset(sqlset_name => 'MYSIMPLESTSUSINGAPI',sqlset_owner => 'SYS' ,replace => True,staging_table_name =>'STS_STBTAB' ,staging_schema_owner => 'DBMGR');


    conn / as sysdba
    SELECT NAME, STATEMENT_COUNT AS "SQLCNT", DESCRIPTION FROM USER_SQLSET;
    MYSIMPLESTSUSINGAPI

    3. 创建 SPA 任务

    VARIABLE t_name VARCHAR2(100);
    EXEC :t_name := DBMS_SQLPA.CREATE_ANALYSIS_TASK(sqlset_name => 'MYSIMPLESTSUSINGAPI', task_name => 'MYSPATASKUSINGAPI');
    print t_name

    Results:

    T_NAME
    -----------------
    MYSPATASKUSINGAPI

    4. 创建和执行变更前的 SPA 任务 in 10.2.0.5 type 为 CONVERT SQLSET,生成11.2.0.1的SPA Trail,采用STS转化方式

    EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(task_name => 'MYSPATASKUSINGAPI', execution_type => 'CONVERT SQLSET', execution_name => 'MY_BEFORE_CHANGE');


    ###5. 做出系统变更
    ###CREATE INDEX t1_idx ON t1 (c1);

    6. 创建和执行变更后的 SPA 任务 in 11.2.0.4 type 为 TEST EXECUTE,从性能数据生成SPA trial

    EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(task_name => 'MYSPATASKUSINGAPI', execution_type => 'TEST EXECUTE', execution_name => 'MY_AFTER_CHANGE');

    7. 对比和分析变更前和变更后的性能

    EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(task_name => 'MYSPATASKUSINGAPI', execution_type => 'COMPARE PERFORMANCE', execution_name => 'MY_EXEC_COMPARE_CPU', execution_params => dbms_advisor.arglist('comparison_metric', 'elapsed_time'));

    EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(task_name => 'MYSPATASKUSINGAPI', execution_type => 'COMPARE PERFORMANCE', execution_name => 'MY_EXEC_COMPARE_BF', execution_params => dbms_advisor.arglist('comparison_metric', 'BUFFER_GETS'));


    -- Generate the Report of cpu

    set long 100000000 longchunksize 100000000 linesize 200 head off feedback off echo off TRIMSPOOL ON TRIM ON
    VAR rep CLOB;
    EXEC :rep := DBMS_SQLPA.REPORT_ANALYSIS_TASK('MYSPATASKUSINGAPI', 'html', 'typical', 'all',execution_name=>'MY_EXEC_COMPARE_CPU');
    ##EXEC :rep := DBMS_SQLPA.REPORT_ANALYSIS_TASK('MYSPATASKUSINGAPI', 'html', 'typical', 'all');
    ##SPOOL C:mydirSPA_detailed.html
    spool /tmp/dba/cpu.html
    PRINT :rep
    SPOOL off


    -- Generate the Report of buffer

    set long 100000000 longchunksize 100000000 linesize 200 head off feedback off echo off TRIMSPOOL ON TRIM ON
    VAR rep CLOB;
    EXEC :rep := DBMS_SQLPA.REPORT_ANALYSIS_TASK('MYSPATASKUSINGAPI', 'html', 'typical', 'all',execution_name=>'MY_EXEC_COMPARE_BF');
    spool /tmp/dba/bf.html
    PRINT :rep
    SPOOL off

    HTML 格式的报告示例:

    下面是 SPA 报告的一部分截屏。报告由3个部分组成,一个部分涉及到变更前和变更后的任务包括 范围,状态,执行起始时间,错误个数和比较的标准;第二个部分总结部分包括了变更带来的负载影响;第三个部分包括了详细的 SQL 信息,比如 SQLID 以及需要比较的度量,比如对负载的影响,执行的频率,以及在这个例子里在变更前后的执行时间这个度量。比如对于 SQL ID 0af4p26041xkv 来说,负载影响是97%。我们要实施的变更对于性能有好的影响,可以把执行时间从12766降低到29。我们还可以看到执行计划在变更后发生了变化。这些信息可以帮助 DBA 进一步关注在特定的问题或者性能退化上,对于当前的这个例子,影响是对性能有提升。

    Image


    下面的截屏显示了在增加了索引后执行计划的变化。这部分信息可以让 DBA 进一步关注在变更前后某个具体 SQL 的执行计划上。对任何 SQL 退化来说,这可以让 DBA 来清楚了解执行计划是如何变化的,并且可以进一步采取计划,比如使用 SQL Tuning Advisor 或者创建 SPM 基线。

    Image

    关于 Real Application Testing 的推荐资源清单:

    • Oracle Real Application Testing Product Information
    • Master Note for Real Application Testing Option (Doc ID 1464274.1)
    • Database Testing: Best Practices (Doc ID 1535885.1)
    • Mandatory Patches for Database Testing Functionality for Current and Earlier Releases (Doc ID 560977.1)

    ##### sample 2

    1 恢复平台 搭建10g性能测试环境 在恢复平台恢复出10g的生产库,作为性能测试环境,参数保持和生产库一致
    2 11g性能测试库 搭建11g性能测试环境 在linux主机进行跨平台迁移,搭建11g性能测试环境
    3 生产环境 抓取sqlset "在生产环境执行附件sql,对生产性能影响不大。


    抓取持续一周。如果有异常,可以立即停掉。"
    4 生产环境 "第三步完成后,
    创建中间表,将sqlset打包到中间表" "exec dbms_sqltune.create_stgtab_sqlset(table_name => 'STS_STBTAB' ,schema_name => 'DBMGR');
    exec dbms_sqltune.pack_stgtab_sqlset(sqlset_name =>'STS_SQLSET' ,sqlset_owner =>'DBMGR' ,staging_table_name =>'STS_STBTAB' ,staging_schema_owner => 'DBMGR' );" 792485

    5 生产环境 导出sqlset "expdp导出DBMGR.STS_STBTAB


    select count(*) from DBMGR.STS_STBTAB;


    exp dbmgr/db1234DBA tables=STS_STBTAB file=/db/cps/archivelog/exp_SQLSET_TAB.dmp log=/db/cps/archivelog/exp_SQLSET_TAB.log FEEDBACK=1000 BUFFER=5000000
    " 如果cow库有sqlset,则直接在cow库按以下拆分步骤操作,sqlset完后拆分后再导入已拆分的sqlset到11g性能测试库。
    将sqlset导入11g性能测试库


    6 10g性能测试库 导入到11g性能测试库 impdp导入DBMGR.STS_STBTAB

    ########-------------将优化集打包到stgtab表里面 中转表过滤 ref    http://ju.outofmemory.cn/entry/77139

    方法1: 

    转换成中转表之后,我们可以再做一次去除重复的操作。当然,你也可以根据module来删除一些不必要的游标。

    1. delete from SPA.SQLSET_TAB a where rowid !=(select max(rowid) from SQLSET_TAB b where a.FORCE_MATCHING_SIGNATURE=b.FORCE_MATCHING_SIGNATURE and a.FORCE_MATCHING_SIGNATURE<>0);
    2.  
       
    3.  
      delete from SPA.SQLSET_TAB where MODULE='PL/SQL Developer';

    方法2:


    create table sts_b as select distinct(to_char(s.force_matching_signature)) b from DBMGR.STS_STBTAB_08 s;

    create index sts_b_1_force on STS_STBTAB_08(to_char(force_matching_signature));

    DECLARE
    T VARCHAR2(50);
    cursor STSCUR IS select b from sts_b;
    STSCUR_1 STS_STBTAB_08%ROWTYPE;
    BEGIN
    OPEN STSCUR;
    LOOP
    fetch STSCUR into T;
    EXIT WHEN STSCUR%NOTFOUND;
    -- DBMS_OUTPUT.PUT_LINE(T);
    select * into STSCUR_1 from ( (select * from STS_STBTAB_08 st where (to_char(st.force_matching_signature)) =T ) order by cpu_time desc) where rownum < 2;
    delete STS_STBTAB_08 where (to_char(force_matching_signature)) =T;
    insert into STS_STBTAB_08 values STSCUR_1;
    commit;
    -- DBMS_OUTPUT.PUT_LINE(STSCUR_1.SQL_ID);
    END LOOP;
    CLOSE STSCUR;
    END;


    7 10g性能测试库 sqlset解包 exec dbms_sqltune.unpack_stgtab_sqlset(sqlset_name => 'STS_SQLSET',sqlset_owner => 'DBMGR' ,replace => True,staging_table_name =>'STS_STBTAB' ,staging_schema_owner => 'DBMGR');
    将sqlset导入10g测试库


    8 10g测试环境 授权 ##grant all on spa_sqlpa to dbmgr;

    grant all on dbms_sqlpa to dbmgr;
    9 10g测试环境 导出导入 "impdp导入DBMGR.STS_STBTAB


    imp dbmgr/dbmgr fromuser=dbmgr touser=dbmgr file=/oraclelv/exp_SQLSET_TAB.dmp feedback=1000 log=/oraclelv/imp_SQLSET_TAB.log BUFFER=5000000
    "
    10 10g测试环境 解包sqlset exec dbms_sqltune.unpack_stgtab_sqlset(sqlset_name => 'STS_SQLSET',sqlset_owner => 'DBMGR' ,replace => True,staging_table_name =>'STS_STBTAB' ,staging_schema_owner => 'DBMGR');

    11 11g性能测试库 创建DBLINK "create public database link to_10g connect to dbmgr identified by xxxxx using 'xxxxxxx'


    create public database link to_10g connect to dbmgr identified by db1234DBA
    using ' (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST =25.10.0.199)(PORT = 1539)) (CONNECT_DATA =(sid = db)))';" 创建到10g测试库的dblink

    第一次执行spa回放,获得10g性能测试环境的数据
    12 11性能测试库 创建task "declare
    mytask varchar2(100);
    begin
    mytask := dbms_sqlpa.create_analysis_task(sqlset_name => 'STS_SQLSET',sqlset_owner => 'DBMGR',task_name => 'TASK_10G');
    END;
    /
    "
    13 11g性能测试库 生成第一次执行task的脚本 (通过db_link 方式)

    "vi spa_10g.sh
    sqlplus -S /nolog <<SQLEnd
    conn / as sysdba
    exec DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(task_name=>'TASK_10G',execution_type=>'test execute',execution_name=>'spa10g',execution_params =>dbms_advisor.argList('DATABASE_LINK','TO_10G','EXECUTE_COUNT',5) ,execution_desc => 'before_change');
    exit
    SQLEnd" 可以看到SPA_DIR下有BEF_TASK_SQLSET_NO_i.sh脚本

    14 11g性能测试库 "执行task,
    执行第一次spa回放" "nohup sh spa_10g.sh > spa_10g.log &
    " 发起目标库执行第一次spa回放

    15 11g性能测试库 查询回放进度 "SELECT owner,task_name,execution_name,a.execution_type,execution_start,execution_last_modified,execution_end,status,b.SOFAR,b.START_TIME,b.LAST_UPDATE_TIME
    from dba_advisor_executions a, v$advisor_progress b where a.execution_name like 'spa10g%';" 计算 792485 笔数据需要多久完成

    第二次执行spa回放,获得11g性能测试环境的数据

    16 11g性能测试库 创建task "declare
    mytask varchar2(100);
    begin
    mytask := dbms_sqlpa.create_analysis_task(sqlset_name => 'STS_SQLSET',sqlset_owner => 'DBMGR',task_name => 'TASK_11G');
    END;
    /
    "

    17 11g性能测试库 生成第二次执行task的脚本 "

    vi spa_11g.sh
    sqlplus -S /nolog <<SQLEnd
    conn / as sysdba
    exec DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(task_name=>'TASK_11G',execution_type=>'test execute',execution_name=>'spa11g_1',execution_params =>dbms_advisor.argList('EXECUTE_COUNT',5) ,execution_desc => 'after_change');
    exit
    SQLEnd" 可以看到SPA_DIR下有AFT_TASK_SQLSET_NO_i.sh脚本

    18 11g性能测试库 "执行task,
    执行第二次spa回放" "nohup sh spa_11g.sh > spa_11g.log &
    " 发起目标库执行第二次spa回放

    19 11g性能测试库 查询回放进度

    "SELECT owner,task_name,execution_name,a.execution_type,execution_start,execution_last_modified,execution_end,status,b.SOFAR,b.START_TIME,b.LAST_UPDATE_TIME
    from dba_advisor_executions a, v$advisor_progress b where a.execution_name like 'spa11g%';"
    分析回放结果

    20 11g性能测试库 取出buffer gets变大的sql进行分析

    21 11g性能测试库 plan改变的sql

     附录:

    3.


    ---------------------------------------------------
    --Step1: 创建名称为STS_SQLSET的SQL_SET.
    ---------------------------------------------------


    BEGIN
    DBMS_SQLTUNE.DROP_SQLSET(
    sqlset_name => 'STS_SQLSET'
    );
    END;
    /


    BEGIN
    DBMS_SQLTUNE.CREATE_SQLSET(SQLSET_NAME => 'STS_SQLSET',
    DESCRIPTION => 'COMPLETE APPLICATION WORKLOAD',
    SQLSET_OWNER =>'DBMGR');
    END;
    /

    ---------------------------------------------------
    --Step2: 初始加载当前数据库中的SQL.
    ---------------------------------------------------

    DECLARE
    STSCUR DBMS_SQLTUNE.SQLSET_CURSOR;
    BEGIN
    OPEN STSCUR FOR
    SELECT VALUE(P)
    FROM TABLE(DBMS_SQLTUNE.SELECT_CURSOR_CACHE('PARSING_SCHEMA_NAME NOT IN (''SYS'', ''SYSTEM'', ''OUTLN'', ''DBSNMP'', ''WMSYS'', ''CTXSYS'', ''XDB'', ''MDSYS'',
    ''ORDPLUGINS'', ''ORDSYS'', ''OLAPSYS'', ''HR'', ''OE'', ''SCOTT'', ''QS_CB'', ''QS_CBADM'', ''QS_ES'', ''QS_OS'', ''QS_CS'', ''QS'', ''QS_ADM'', ''QS_WS'', ''DIP'', ''TSMSYS'', ''EXFSYS'',
    ''LBACSYS'', ''TRACESVR'', ''AURORA$JIS$UTILITY$'', ''OSE$HTTP$ADMIN'', ''DBMGR'', ''OVSEE'', ''DBMONOPR'')
    AND PLAN_HASH_VALUE <> 0 AND UPPER(SQL_TEXT) NOT LIKE ''%TABLE_NAME%''',
    NULL, NULL, NULL, NULL, 1, NULL,
    'ALL')) P;
    -- POPULATE THE SQLSET
    DBMS_SQLTUNE.LOAD_SQLSET(SQLSET_NAME => 'STS_SQLSET',
    POPULATE_CURSOR => STSCUR,
    COMMIT_ROWS => 100,
    SQLSET_OWNER => 'DBMGR');
    CLOSE STSCUR;
    COMMIT;
    EXCEPTION
    WHEN OTHERS THEN
    RAISE;
    END;
    /


    ---------------------------------------------------
    --Step3: 增量抓取数据库中的SQL, 会连续抓取7天,每小时抓取一次,Sessions一直持续7天. 这一步用shell脚本在后台执行。


    BEGIN
    DBMS_SQLTUNE.CAPTURE_CURSOR_CACHE_SQLSET(SQLSET_NAME => 'STS_SQLSET',
    TIME_LIMIT => 345600,
    REPEAT_INTERVAL => 3600,
    CAPTURE_OPTION => 'MERGE',
    CAPTURE_MODE => DBMS_SQLTUNE.MODE_ACCUMULATE_STATS,
    BASIC_FILTER => 'PARSING_SCHEMA_NAME NOT IN (''SYS'', ''SYSTEM'', ''OUTLN'', ''DBSNMP'', ''WMSYS'', ''CTXSYS'', ''XDB'', ''MDSYS'',
    ''ORDPLUGINS'', ''ORDSYS'', ''OLAPSYS'', ''HR'', ''OE'', ''SCOTT'', ''QS_CB'', ''QS_CBADM'', ''QS_ES'', ''QS_OS'', ''QS_CS'', ''QS'', ''QS_ADM'', ''QS_WS'', ''DIP'', ''TSMSYS'', ''EXFSYS'',''LBACSYS'', ''TRACESVR'', ''AURORA$JIS$UTILITY$'', ''OSE$HTTP$ADMIN'', ''DBMGR'', ''OVSEE'', ''DBMONOPR'')
    AND PLAN_HASH_VALUE <> 0 AND UPPER(SQL_TEXT) NOT LIKE ''%TABLE_NAME%''',
    SQLSET_OWNER => 'DBMGR');
    END;
    /


    20.

    Select *
    From (Select b.*, dbms_lob.substr(st.sql_text, 3000) sql_text
    From SYS.Wrh$_Sqltext st,
    (Select task_name,
    sql_id,
    executions,
    detal_buffer_gets,
    bf_buffer_gets,
    af_buffer_gets,
    bf_plan_hash_value,
    bf_rows_processed,
    af_plan_hash_value,
    af_ROWS_PROCESSED
    From (Select task_name,
    sql_id,
    bf_executions executions,
    round(af_buffer_gets / af_EXECUTIONS) -
    round(bf_buffer_gets / bf_executions) detal_buffer_gets,
    round(bf_buffer_gets / bf_executions) bf_buffer_gets,
    round(af_buffer_gets / af_EXECUTIONS) af_buffer_gets,
    bf_plan_hash_value,
    bf_rows_processed / bf_executions bf_rows_processed,
    af_plan_hash_value,
    af_ROWS_PROCESSED / af_EXECUTIONS af_ROWS_PROCESSED
    From (Select bf.task_name,
    bf.sql_id,
    bf.executions bf_executions,
    bf.plan_hash_value bf_plan_hash_value,
    bf.buffer_gets bf_buffer_gets,
    bf.rows_processed bf_rows_processed,
    af.plan_hash_value af_plan_hash_value,
    af.buffer_gets af_buffer_gets,
    af.executions af_executions,
    af.rows_processed af_rows_processed
    From dba_advisor_sqlstats af,
    dba_advisor_sqlstats bf
    Where af.execution_name='SPA11G'
    And af.task_name like '%TASK_11G%'
    And bf.task_name like '%TASK_10G%'
    And bf.execution_name='SPA10G'
    And bf.sql_id = af.sql_id))
    Where detal_buffer_gets > 0

    and af_plan_hash_value ! = bf_plan_hash_value) b
    Where st.sql_id = b.sql_id
    Order By detal_buffer_gets Desc)
    Where sql_text Not Like '%Analyze(%'
    And sql_text Not Like '%SELECT /* DS_SVC */%'
    And sql_text Not Like '%/* OPT_DYN_SAMP */%';

    21.

    Select st.sql_id,
    sst.executions,
    dbms_lob.substr(st.sql_text, 3000) sql_text
    From sys.wrh$_sqltext st,
    dba_sqlset_statements sst,
    (Select Distinct sql_id
    From (Select sql_id,
    operation,
    options,
    object_name,
    object_alias,
    object_type,
    Id,
    parent_id,
    depth
    From dba_advisor_sqlplans af
    Where af.task_name = 'TASK_11G' And af.execution_name = 'SPA11G'
    Minus
    Select sql_id,
    operation,
    options,
    object_name,
    object_alias,
    object_type,
    Id,
    parent_id,
    depth
    From dba_advisor_sqlplans bf
    Where bf.task_name = 'TASK_10G' And bf.execution_name = 'SPA10G'
    )) cp
    Where st.sql_id = cp.sql_id
    And sst.sql_id = cp.sql_id
    And st.sql_text Not Like '%Analyze(%'
    And st.sql_text Not Like '%SELECT /* DS_SVC */%'
    And st.sql_text Not Like '%/* OPT_DYN_SAMP */%'
    And sst.sqlset_name Like 'STS_SQLSETNO%'
    ;

    ###refer 1

    http://www.cnblogs.com/jyzhao/p/9210517.html

    生产端:Windows 2008 + Oracle 10.2.0.5
    测试端:RHEL 6.5 + Oracle 11.2.0.4
    需求:因为Oracle跨越大版本,优化器、新特性变动较多,需要进行SPA测试比对前后期性能差异。
    说明:本文是根据DBA Travel的SPA参考规范文档(在此致谢Travel同学),结合实际某客户需求整理的整个测试过程。为了更真实的反映整个过程,在生产端使用swingbench压力测试软件持续运行了一段时间,模拟真实的业务压力。

    1.SPA测试流程

    为了尽可能的减小对正式生产库的性能影响,本次SPA测试只是从AWR资料库中的SQL数据转化而来的SQL Tuning Set进行整体的SQL性能测试。

    本次SPA测试主要分为以下几个步骤:
    在生产库端:

    1. 环境准备:创建SPA测试专用用户
    2. 采集数据: a) 在生产库转化AWR中SQL为SQL Tuning Set b) 在生产库从现有SQL Tuning Set提取SQL
    3. 导出数据:打包(pack)转化后的SQL Tuning Set,并导出传输到测试服务器

    在测试库端:

    1. 环境准备:创建SPA测试专用用户
    2. 测试准备:导入SQL Tuning Set表,并解包(unpack),创建SPA分析任务
    3. 前期性能:从SQL Tuning Set中转化得出10g的性能Trail
    4. 后期性能:在11g测试数据库中执行SQL Tuning Set中SQL,生成11g性能Trail
    5. 对比分析:执行对比分析任务,分别按执行时间,CPU时间和逻辑读三个维度进行
    6. 汇总报告:取出对比报告,对每个维度分别取出All,Unsupport,Error 3类报告

    总结报告:

    1. 总结报告:分析汇总报告,优化其中的性能下降SQL,编写SPA测试报告

    2.SPA操作流程

    2.1 本文使用的命名规划

    类型                 规划
    SQLSET             ORCL_SQLSET_201806
    Analysis Task        SPA_TASK_201806
    STGTAB             ORCL_STSTAB_201806
    Dmpfile            ORCL_STSTAB_201806.dmp

    2.2 生产端:环境准备

    conn / as sysdba
    CREATE USER SPA IDENTIFIED BY SPA DEFAULT TABLESPACE SYSAUX;
    GRANT DBA TO SPA;
    GRANT ADVISOR TO SPA;
    GRANT SELECT ANY DICTIONARY TO SPA;
    GRANT ADMINISTER SQL TUNING SET TO SPA;

    2.3 生产端:采集数据
    1). 获取AWR快照的边界ID

    SET LINES 188 PAGES 1000
    COL SNAP_TIME FOR A22
    COL MIN_ID NEW_VALUE MINID
    COL MAX_ID NEW_VALUE MAXID
    SELECT MIN(SNAP_ID) MIN_ID, MAX(SNAP_ID) MAX_ID
      FROM DBA_HIST_SNAPSHOT
     WHERE END_INTERVAL_TIME > trunc(sysdate)-10
     ORDER BY 1;

    2). 创建SQL Set

    --连接用户
    conn SPA/SPA
    
    --如果之前有这个SQLSET的名字,可以这样删除
    EXEC DBMS_SQLTUNE.DROP_SQLSET (SQLSET_NAME  => 'ORCL_SQLSET_201806', SQLSET_OWNER => 'SPA');
    
    --新建SQLSET:ORCL_SQLSET_201806
    EXEC DBMS_SQLTUNE.CREATE_SQLSET ( -
                      SQLSET_NAME  => 'ORCL_SQLSET_201806', -
                      DESCRIPTION  => 'SQL Set Create at : '||TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), -
                      SQLSET_OWNER => 'SPA');

    3). 转化AWR数据中的SQL数据,将其中的SQL载入到SQL Set中

    DECLARE
      SQLSET_CUR DBMS_SQLTUNE.SQLSET_CURSOR;
    BEGIN
      OPEN SQLSET_CUR FOR
        SELECT VALUE(P) FROM TABLE(
               DBMS_SQLTUNE.SELECT_WORKLOAD_REPOSITORY( 16, 24,
                            'PARSING_SCHEMA_NAME NOT IN (''SYS'', ''SYSTEM'')',
                            NULL, NULL, NULL, NULL, 1, NULL, 'ALL')) P;
      DBMS_SQLTUNE.LOAD_SQLSET(
                   SQLSET_NAME => 'ORCL_SQLSET_201806',
                   SQLSET_OWNER => 'SPA',
                   POPULATE_CURSOR => SQLSET_CUR,
                   LOAD_OPTION => 'MERGE',
                   UPDATE_OPTION => 'ACCUMULATE');
      CLOSE SQLSET_CUR;
        END;
    /           

    4). 打包SQL Set

    DROP TABLE SPA.JYZHAO_SQLSETTAB_20180106;
    EXEC DBMS_SQLTUNE.CREATE_STGTAB_SQLSET ('ORCL_STSTAB_201806', 'SPA', 'SYSAUX');
    EXEC DBMS_SQLTUNE.PACK_STGTAB_SQLSET ( -
                      SQLSET_NAME          => 'ORCL_SQLSET_201806', -
                      SQLSET_OWNER         => 'SPA', -
                      STAGING_TABLE_NAME   => 'ORCL_STSTAB_201806', -
                      STAGING_SCHEMA_OWNER => 'SPA');

    2.4 生产端:导出数据
    1). 在操作系统中,导出打包后的SQL Set数据

    cat > ./export_sqlset_201806.par <<EOF
    USERID='SPA/SPA'
    FILE=ORCL_STSTAB_201806.dmp
    LOG=exp_spa_sqlset_201806.log
    TABLES=ORCL_STSTAB_201806
    DIRECT=N
    BUFFER=10240000
    STATISTICS=NONE
    EOF

    注意:这里DIRECT=Y参数在遇到问题后尝试改为了DIRECT=N,默认也是N。

    set NLS_LANG=AMERICAN_AMERICA.US7ASCII
    exp PARFILE=export_sqlset_201806.par

    注意:NLS_LANG变量是Oracle的变量,设置字符集和数据库字符集一致,避免发生错误转换。

    2). 将导出后的Dump文件传输到测试服务器
    将 ORCL_STSTAB_201806.dmp 传输到 目标服务器 /orabak/spa下。

    2.5 测试端:环境准备

    conn / as sysdba
    CREATE USER SPA IDENTIFIED BY SPA DEFAULT TABLESPACE SYSAUX;
    GRANT DBA TO SPA;
    GRANT ADVISOR TO SPA;
    GRANT SELECT ANY DICTIONARY TO SPA;
    GRANT ADMINISTER SQL TUNING SET TO SPA;

    2.6 测试端:测试准备
    在进行SPA测试前需要准备测试环境,包括导入生产库中的SQL Set,对其进行解包(unpack)操作,并创建SPA分析任务。
    1). 在操作系统中,执行导入命令,导入SQL Set表

    cat > ./import_sqlset_201806.par <<EOF
    USERID='SPA/SPA'
    FILE=ORCL_STSTAB_201806.dmp
    LOG=imp_spa_sqlset_201806.log
    FULL=Y
    EOF
    
    export NLS_LANG=AMERICAN_AMERICA.US7ASCII
    imp PARFILE=import_sqlset_201806.par

    2). 解包(unpack)SQL Set

    conn SPA/SPA
    EXEC DBMS_SQLTUNE.UNPACK_STGTAB_SQLSET (-
                      SQLSET_NAME          => 'ORCL_SQLSET_201806', -
                      SQLSET_OWNER         => 'SPA', -
                      REPLACE              => TRUE, -
                      STAGING_TABLE_NAME   => 'ORCL_STSTAB_201806', -
                      STAGING_SCHEMA_OWNER => 'SPA');

    3). 创建SPA分析任务

    VARIABLE SPA_TASK  VARCHAR2(64);
    EXEC :SPA_TASK := DBMS_SQLPA.CREATE_ANALYSIS_TASK(  -
                                 TASK_NAME    => 'SPA_TASK_201806', -
                                 DESCRIPTION  => 'SPA Analysis task at : '||TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), -
                                 SQLSET_NAME  => 'ORCL_SQLSET_201806', -
                                 SQLSET_OWNER => 'SPA');

    2.7 测试端:前期性能
    在测试服务器中,可以直接从SQL Tuning Set中转化得到所有SQL在10g数据库中的执行效率,得到10g中的SQL Trail。

    EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK( -
                    TASK_NAME      => 'SPA_TASK_201806', -
                    EXECUTION_NAME => 'EXEC_10G_201806', -
                    EXECUTION_TYPE => 'CONVERT SQLSET', -
                    EXECUTION_DESC => 'Convert 10g SQLSET for SPA Task at : '||TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));

    2.8 测试端:后期性能
    在测试服务器(运行11g数据库)中,需要在本地数据库(11g)测试运行SQL Tuning Set中的SQL语句,分析所有语句在11g环境中的执行效率,得到11g中的SQL Trail。

    vi spa2.sh
     
    echo "WARNING: SPA2 Start @`date`"
    sqlplus SPA/SPA << EOF!
    EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK( -
                    TASK_NAME      => 'SPA_TASK_201806', -
                    EXECUTION_NAME => 'EXEC_11G_201806', -
                    EXECUTION_TYPE => 'TEST EXECUTE', -
                    EXECUTION_DESC => 'Execute SQL in 11g for SPA Task at : '||TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));
    exit
    EOF!
    echo "WARNING:SPA2 OK @`date`"
     
    nohup sh spa2.sh &      

    2.9 测试端:性能对比 
    得到两次SQL Trail之后,可以对比两次Trial之间的SQL执行性能,可以从不同的维度对两次Trail中的所有SQL进行对比分析,主要关注的维度有:SQL执行时间,SQL执行的CPU时间,SQL执行的逻辑读。

    1). 对比两次Trail中的SQL执行时间

    conn SPA/SPA
    EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK( -
                    TASK_NAME      => 'SPA_TASK_201806', -
                    EXECUTION_NAME => 'COMPARE_ET_201806', -
                    EXECUTION_TYPE => 'COMPARE PERFORMANCE', -
                    EXECUTION_PARAMS => DBMS_ADVISOR.ARGLIST( -
                                                     'COMPARISON_METRIC', 'ELAPSED_TIME', -
                                                     'EXECUTE_FULLDML', 'TRUE', -
                                                     'EXECUTION_NAME1','EXEC_10G_201806', -
                                                     'EXECUTION_NAME2','EXEC_11G_201806'), -
                    EXECUTION_DESC => 'Compare SQLs between 10g and 11g at :'||TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));

    2). 对比两次Trail中的SQL执行的CPU时间

    EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK( -
                    TASK_NAME      => 'SPA_TASK_201806', -
                    EXECUTION_NAME => 'COMPARE_CT_201806', -
                    EXECUTION_TYPE => 'COMPARE PERFORMANCE', -
                    EXECUTION_PARAMS => DBMS_ADVISOR.ARGLIST( -
                                                     'COMPARISON_METRIC', 'CPU_TIME', -
                                                     'EXECUTION_NAME1','EXEC_10G_201806', -
                                                     'EXECUTION_NAME2','EXEC_11G_201806'), -
                    EXECUTION_DESC => 'Compare SQLs between 10g and 11g at :'||TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));

    3). 对比两次Trail中的SQL执行的逻辑读

    EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK( -
                    TASK_NAME      => 'SPA_TASK_201806', -
                    EXECUTION_NAME => 'COMPARE_BG_201806', -
                    EXECUTION_TYPE => 'COMPARE PERFORMANCE', -
                    EXECUTION_PARAMS => DBMS_ADVISOR.ARGLIST( -
                                                     'COMPARISON_METRIC', 'BUFFER_GETS', -
                                                     'EXECUTION_NAME1','EXEC_10G_201806', -
                                                     'EXECUTION_NAME2','EXEC_11G_201806'), -
                    EXECUTION_DESC => 'Compare SQLs between 10g and 11g at :'||TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));

    2.10 测试端:汇总报告
    执行对比分析任务之后,就可以取出对应的对比分析任务的结果报告,主要关注的报告类型有:汇总SQL报告,错误SQL报告以及不支持SQL报告。

    a) 获取执行时间全部报告

    conn SPA/SPA
    ALTER SESSION SET EVENTS='31156 TRACE NAME CONTEXT FOREVER, LEVEL 0X400';
    SET LINES 1111 PAGES 50000 LONG 1999999999 TRIM ON TRIMS ON SERVEROUTPUT ON SIZE UNLIMITED
    SPOOL elapsed_all.html
    SELECT XMLTYPE(DBMS_SQLPA.REPORT_ANALYSIS_TASK('SPA_TASK_201806','HTML','ALL','ALL',NULL,1000,'COMPARE_ET_201806')).GETCLOBVAL(0,0) FROM DUAL;
    spool off

    b) 获取执行时间下降报告

    ALTER SESSION SET EVENTS='31156 TRACE NAME CONTEXT FOREVER, LEVEL 0X400';
    SET LINES 1111 PAGES 50000 LONG 1999999999 TRIM ON TRIMS ON SERVEROUTPUT ON SIZE UNLIMITED
    SPOOL elapsed_regressed.html
    SELECT XMLTYPE(DBMS_SQLPA.REPORT_ANALYSIS_TASK('SPA_TASK_201806','HTML','REGRESSED','ALL',NULL,1000,'COMPARE_ET_201806')).GETCLOBVAL(0,0) FROM DUAL;
    spool off

    c) 获取逻辑读全部报告

    ALTER SESSION SET EVENTS='31156 TRACE NAME CONTEXT FOREVER, LEVEL 0X400';
    SET LINES 1111 PAGES 50000 LONG 1999999999 TRIM ON TRIMS ON SERVEROUTPUT ON SIZE UNLIMITED
    SPOOL buffer_all.html
    SELECT XMLTYPE(DBMS_SQLPA.REPORT_ANALYSIS_TASK('SPA_TASK_201806','HTML','ALL','ALL',NULL,1000,'COMPARE_BG_201806')).GETCLOBVAL(0,0) FROM DUAL;
    spool off

    d) 获取逻辑读下降报告

    ALTER SESSION SET EVENTS='31156 TRACE NAME CONTEXT FOREVER, LEVEL 0X400';
    SET LINES 1111 PAGES 50000 LONG 1999999999 TRIM ON TRIMS ON SERVEROUTPUT ON SIZE UNLIMITED
    SPOOL buffer_regressed.html
    SELECT XMLTYPE(DBMS_SQLPA.REPORT_ANALYSIS_TASK('SPA_TASK_201806','HTML','REGRESSED','ALL',NULL,1000,'COMPARE_BG_201806')).GETCLOBVAL(0,0) FROM DUAL;
    spool off

    e) 获取错误报告

    ALTER SESSION SET EVENTS='31156 TRACE NAME CONTEXT FOREVER, LEVEL 0X400';
    SET LINES 1111 PAGES 50000 LONG 1999999999 TRIM ON TRIMS ON SERVEROUTPUT ON SIZE UNLIMITED
    SPOOL error.html
    SELECT XMLTYPE(DBMS_SQLPA.REPORT_ANALYSIS_TASK('SPA_TASK_201806','HTML','ERRORS','ALL',NULL,1000,'COMPARE_ET_201806')).GETCLOBVAL(0,0) FROM DUAL;
    spool off

    f) 获取不支持报告

    ALTER SESSION SET EVENTS='31156 TRACE NAME CONTEXT FOREVER, LEVEL 0X400';
    SET LINES 1111 PAGES 50000 LONG 1999999999 TRIM ON TRIMS ON SERVEROUTPUT ON SIZE UNLIMITED
    SPOOL unsupported.html
    SELECT XMLTYPE(DBMS_SQLPA.REPORT_ANALYSIS_TASK('SPA_TASK_201806','HTML','UNSUPPORTED','ALL',NULL,1000,'COMPARE_ET_201806')).GETCLOBVAL(0,0) FROM DUAL;
    spool off

    g) 获取执行计划变化报告

    ALTER SESSION SET EVENTS='31156 TRACE NAME CONTEXT FOREVER, LEVEL 0X400';
    SET LINES 1111 PAGES 50000 LONG 1999999999 TRIM ON TRIMS ON SERVEROUTPUT ON SIZE UNLIMITED
    SPOOL changed_plans.html
    SELECT XMLTYPE(DBMS_SQLPA.REPORT_ANALYSIS_TASK('SPA_TASK_201806','HTML','CHANGED_PLANS','ALL',NULL,1000,'COMPARE_ET_201806')).GETCLOBVAL(0,0) FROM DUAL;
    spool off

    3.SPA环境清理

    3.1 查看SQLSET

    conn SPA/SPA
    select owner,name,STATEMENT_COUNT from dba_sqlset;

    3.2 查看分析任务

    select owner,task_id,task_name,created,LAST_MODIFIED,STATUS from DBA_ADVISOR_TASKS  where task_name like upper('%&task_name%') order by 2;
    SPA_TASK_201806

    3.3 删除ANALYSIS_TASK

    exec dbms_sqlpa.DROP_ANALYSIS_TASK('SPA_TASK_201806');

    3.4 删除sqlset

    exec dbms_sqltune.DROP_SQLSET('ORCL_SQLSET_201806');

    如果删除时出现异常情况"ORA-13757",提示STS是活动的,可以尝试使用下面SQL修改后再进行删除。

    delete from wri$_sqlset_references
        where sqlset_id in (select id
        from wri$_sqlset_definitions
        where name in ('ORCL_SQLSET_201806','ORCL_SQLSET_201806'));
    commit;

    3.5 删除用户
    删除SPA用户(两端)

    drop user spa cascade;
    AlfredZhao©版权所有「从Oracle起航,领略精彩的IT技术。」

    ####refer

    http://www.lunar2013.com/2015/05/spasql%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90%E5%99%A8%E7%9A%84%E4%BD%BF%E7%94%A8-1-%E6%94%B6%E9%9B%86%E5%92%8C%E8%BF%81%E7%A7%BBsql-tuning-set.html


    ### section 1
    SPA(SQL Performance Analyzer , SQL 性能分析器),是11g引入的新功能,主要用于预测潜在的更改对 SQL 查询工作量的性能影响。
    一般有几种情况下,我们会建议做SPA:
    1,OS版本发生变化
    2,硬件发生变化
    3,数据库版本的升级
    4,实施某些优化建议
    5, 收集统计信息
    6,更改数据库参数
    等等
    .
    SPA的主要实施步骤如下:
    1, 在生产系统上捕捉SQL负载,并生成SQL Tuning Set;
    2, 创建一个中转表,将SQL Tuning Set导入到中转表,导出中转表并传输到测试库;
    3, 导入中转表,并解压中转表的数据到SQL Tuning Set;
    4, 创建SPA任务,先生成10g的trail,然后在11g中再生成11g的trail;
    5, 执行比较任务,再生成SPA报告;
    6, 分析性能退化的SQL语句;
    .
    我这里的例子是,将一根数据库从10.2.0.1升级到11.2.0.4.
    1,在源库创建spa用户:

    create user LUNAR identified by LUNAR;
    grant connect,resource,dba to LUNAR;

    10:38:37 lunar@LUNAR>select username,default_tablespace,temporary_tablespace
    10:41:41 2 from dba_users
    10:41:41 3 where username in ('LUNAR','SPA')
    10:41:41 4 order by 1,2;

    USERNAME DEFAULT_TABLESPACE TEMPORARY_TABLESPACE
    ------------------------------ ------------------------------ ------------------------------
    LUNAR USERS TEMP

    Elapsed: 00:00:00.27
    10:41:41 lunar@LUNAR>
    2,检查SYSAUX空间是否足够

    09:26:38 sys@LUNAR>@ts

    Name TS Type All Size Max Size Free Size Max Free Pct. Free Max Free%
    ------------------------------ ------------ ---------- ---------- ---------- ---------- --------- ---------
    UNDOTBS1 UNDO 148,433 221,521 19,467 92,555 13 42
    LUNAR_IDX PERMANENT 352,256 352,256 84,272 84,272 24 24
    LUNAR_DAT PERMANENT 1,048,576 1,048,576 258,728 258,728 25 25
    LUNAR_TESTS PERMANENT 251,904 251,904 139,424 139,424 55 55
    LUNAR_TESTS_IDX PERMANENT 329,728 329,728 196,351 196,351 60 60
    USERS PERMANENT 4,096 32,768 2,582 31,254 63 95
    SYSAUX PERMANENT 4,096 32,768 2,786 31,458 68 96
    SYSTEM PERMANENT 4,096 32,768 2,882 31,554 70 96

    8 rows selected.

    Elapsed: 00:00:00.07
    09:26:40 sys@LUNAR>
    3,创建SQL优化器:

    conn LUNAR/LUNAR
    10:33:30 lunar@LUNAR>exec dbms_sqltune.create_sqlset('Lunar_11201STS_LUNAR');

    PL/SQL procedure successfully completed.

    Elapsed: 00:00:00.11
    10:34:25 lunar@LUNAR>
    4,往SQL优化其中,加载优化集

    1). 从AWR快照中加载
    11:31:55 lunar@LUNAR>select INSTANCE_NUMBER ,min(snap_id),max(snap_id) from dba_hist_snapshot group by INSTANCE_NUMBER;

    INSTANCE_NUMBER MIN(SNAP_ID) MAX(SNAP_ID)
    --------------- ------------ ------------
    1 19355 19555

    Elapsed: 00:00:00.01
    11:32:12 lunar@LUNAR>
    b).加载2个快照之间的所有查询(这一步大概执行了4分钟)

    11:33:12 lunar@LUNAR>declare
    11:33:14 2 own VARCHAR2(30) := 'LUNAR';
    11:33:14 3 bid NUMBER := '&begin_snap';
    11:33:14 4 eid NUMBER := '&end_snap';
    11:33:14 5 stsname VARCHAR2(30) :='Lunar_11201STS_LUNAR';
    11:33:14 6 sts_cur dbms_sqltune.sqlset_cursor;
    11:33:14 7 begin
    11:33:14 8 open sts_cur for
    11:33:14 9 select value(P) from table(dbms_sqltune.select_workload_repository(bid,eid, null, null, null, null, null, 1, null, 'ALL')) P;
    11:33:14 10 dbms_sqltune.load_sqlset(sqlset_name => stsname,populate_cursor => sts_cur,load_option => 'MERGE');
    11:33:14 11 end;
    11:33:14 12 /
    Enter value for begin_snap: 19355
    old 3: bid NUMBER := '&begin_snap';
    new 3: bid NUMBER := '19355';
    Enter value for end_snap: 19555
    old 4: eid NUMBER := '&end_snap';
    new 4: eid NUMBER := '19555';

    PL/SQL procedure successfully completed.

    Elapsed: 00:03:07.05
    11:36:29 lunar@LUNAR>
    c) 验证创建的SQL优化集

    10:52:58 lunar@LUNAR>select NAME,OWNER,CREATED,STATEMENT_COUNT, LAST_MODIFIED FROM DBA_SQLSET;

    NAME OWNER CREATED STATEMENT_COUNT LAST_MODIFIED
    ------------------------------ ------------------------------ ------------------- --------------- -------------------
    Lunar_11201STS_LUNAR LUNAR 2015-04-18 10:34:25 921 2015-04-18 10:38:27

    Elapsed: 00:00:00.06
    10:53:03 lunar@LUNAR>
    2). 如果需要,可以从AWR快照中加载指定sql_id和plan_hash_value的sql语句

    12:06:31 lunar@LUNAR>SELECT sql_id, substr(sql_text, 1, 50) sql
    12:06:32 2 FROM TABLE( DBMS_SQLTUNE.select_sqlset ('Lunar_11201STS_LUNAR'))
    12:06:32 3 where sql_id in ('34xbj7bv7suyk','gxsfh4gm276d3');

    SQL_ID SQL
    ------------- --------------------------------------------------
    34xbj7bv7suyk UPDATE "LUNAR_PRD".MDRT_1472A$ set info= :1 where ro
    gxsfh4gm276d3 update LUNARINFO t set TIME=:1, LUNARMARK=:2, LO

    Elapsed: 00:00:01.14
    12:06:34 lunar@LUNAR>
    3). 从当前游标缓存中加载

    DECLARE
    cur sys_refcursor;
    BEGIN
    OPEN cur FOR
    SELECT value(P)
    FROM TABLE(dbms_sqltune.select_cursor_cache('parsing_schema_name <> ''SYS''',NULL,NULL,NULL,NULL,1,NULL,'ALL')) p;
    dbms_sqltune.load_sqlset('Lunar_11201STS_LUNAR', cur);
    CLOSE cur;
    END;
    /
    上述过程一般执行时间比较长,因此,通常放到后台执行。
    这里我们看到加载的SQL明显增加了很多:

    12:55:02 sys@LUNAR>select NAME,OWNER,CREATED,STATEMENT_COUNT FROM DBA_SQLSET;

    NAME OWNER CREATED STATEMENT_COUNT
    ------------------------------ ------------------------------ ------------------- ---------------
    Lunar_11201STS_LUNAR LUNAR 2015-04-18 11:31:55 41928

    12:57:11 sys@LUNAR>

    执行完上述所有操作后,我们就可以将这个SQL TUNING SET迁移到新的环境,进行分析,具体过程如下:
    1,在新库中创建SQL优化器用户

    create user LUNAR identified by LUNAR;
    grant connect,resource,dba to LUNAR;
    2,检查SYSAUX空间是否足够

    3,在源库上执行打包SQL TUNING SET的操作,然后exp/imp到新库上

    [oracle@lunardb tmp]$ ss

    SQL*Plus: Release 11.2.0.1.0 Production on Sat Apr 18 23:22:26 2015

    Copyright (c) 1982, 2009, Oracle. All rights reserved.


    Connected to:
    Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
    With the Partitioning, OLAP, Data Mining and Real Application Testing options

    23:22:26 sys@GPS>conn LUNAR/LUNAR
    Connected.
    23:22:28 lunar@GPS>BEGIN
    23:22:33 2 DBMS_SQLTUNE.create_stgtab_sqlset(table_name => 'SQLSET_TAB_LUNAR',
    23:22:34 3 schema_name => 'LUNAR',
    23:22:34 4 tablespace_name => 'USERS');
    23:22:34 5 END;
    23:22:34 6 /

    PL/SQL procedure successfully completed.

    Elapsed: 00:00:01.32
    23:22:36 lunar@GPS>
    3,打包SQL TUNING SET的操作,然后exp/imp到新库上

    conn LUNAR/LUNAR

    BEGIN
    DBMS_SQLTUNE.pack_stgtab_sqlset(sqlset_name => 'Lunar_11201STS_GPS',
    sqlset_owner => 'LUNAR',
    staging_table_name => 'SQLSET_TAB_LUNAR',
    staging_schema_owner => 'LUNAR');
    END;
    /
    执行过程中,我们可以监控一下:

    [oracle@lunardb tmp]$ ss

    SQL*Plus: Release 11.2.0.1.0 Production on Sat Apr 18 23:26:18 2015

    Copyright (c) 1982, 2009, Oracle. All rights reserved.


    Connected to:
    Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
    With the Partitioning, OLAP, Data Mining and Real Application Testing options

    23:26:18 sys@GPS>select count(*) from LUNAR.SQLSET_TAB_LUNAR;

    COUNT(*)
    ----------
    496641

    Elapsed: 00:00:00.57
    23:28:04 sys@GPS>
    exp LUNAR/LUNAR tables=SQLSET_TAB_LUNAR file=/u01/oradata/tmp/exp_SQLSET_TAB_LUNAR.dmp log=/u01/oradata/tmp/exp_SQLSET_TAB_LUNAR.log FEEDBACK=1000 BUFFER=5000000

    4,在新库上执行导入SQL TUNING SET的表(LUNAR.SQLSET_TAB_LUNAR)
    imp LUNAR/LUNAR fromuser=LUNAR touser=LUNAR file=/u01/oradata/tmp/exp_SQLSET_TAB_LUNAR.dmp feedback=1000 log=/u01/oradata/tmp/imp_SQLSET_TAB_LUNAR.log BUFFER=5000000

    ### section 2


    1,查看当前STS中的SQL数量:

    09:52:42 LUNAR@ lunardb> select count(*) from LUNAR.SQLSET_TAB_LUNAR;

    COUNT(*)
    ----------
    496641

    Elapsed: 00:00:00.24
    09:53:13 LUNAR@ lunardb>
    删除一些没用的:

    LUNAR@ lunardb> delete from LUNAR.SQLSET_TAB_LUNAR
    where (PARSING_SCHEMA_NAME in ('LUNAR', 'GGUSR','EXFSYS','SYS') )
    or ( module in ('PL/SQL Developer','SQL*Plus','sqlplus.exe','plsqldev.exe','DBMS_SCHEDULER') );

    701 rows deleted.

    Elapsed: 00:00:00.96
    10:07:34 LUNAR@ lunardb> commit;

    Commit complete.

    Elapsed: 00:00:00.00
    10:07:38 LUNAR@ lunardb>

    2,在新库创建Lunar_11201STS_LUNAR SQLSET集

    create user LUNARSPA identified by LUNARSPA;
    grant connect,resource,dba to LUNARSPA;

    10:24:41 LUNAR@ lunardb>
    10:24:41 2 from dba_users
    10:24:41 3 where username in ('LUNAR','LUNARSPA')
    10:24:41 4 order by 1,2;

    USERNAME DEFAULT_TABLESPACE TEMPORARY_TABLESPACE
    ------------------------------ ------------------------------ ------------------------------
    LUNAR USERS TEMP
    LUNARSPA USERS TEMP

    Elapsed: 00:00:00.03
    10:24:42 LUNAR@ lunardb>
    —(2)使用LUNAR用户,创建STS:Lunar_11204STS_LUNAR

    10:24:42 LUNAR@ lunardb> conn LUNARSPA/LUNARSPA
    Connected.
    10:25:33 LUNARSPA@ lunardb> exec DBMS_SQLTUNE.create_sqlset(sqlset_name => 'Lunar_11204STS_LUNAR');

    PL/SQL procedure successfully completed.

    Elapsed: 00:00:00.05
    10:25:40 LUNARSPA@ lunardb>
    —(2)使用LUNARSPA用户,将源库的LUNAR.Lunar_11201STS_LUNAR的SQL优化器映射到LUNARSPA.Lunar_11204STS_LUNAR

    10:28:24 LUNARSPA@ lunardb> select NAME,OWNER,CREATED,STATEMENT_COUNT FROM DBA_SQLSET;

    NAME OWNER CREATED STATEMENT_COUNT
    ------------------------------ ------------------------------ ------------------- ---------------
    Lunar_11204STS_LUNAR LUNARSPA 2015-04-19 10:25:40 0

    Elapsed: 00:00:00.00


    10:40:44 LUNARSPA@ lunardb> exec dbms_sqltune.remap_stgtab_sqlset(old_sqlset_name =>'Lunar_11201STS_LUNAR',old_sqlset_owner => 'LUNAR', new_sqlset_name => 'Lunar_11204STS_LUNAR',new_sqlset_owner => 'LUNARSPA', staging_table_name => 'SQLSET_TAB_LUNAR',staging_schema_owner => 'LUNAR');

    PL/SQL procedure successfully completed.

    Elapsed: 00:00:09.39
    10:41:06 LUNARSPA@ lunardb>
    使用LUNARSPA用户执行remap:

    BEGIN
    DBMS_SQLTUNE.unpack_stgtab_sqlset(
    sqlset_name => 'Lunar_11201STS_LUNAR',
    sqlset_owner => 'SPA',
    replace => TRUE,
    staging_table_name => 'SQLSET_TAB',
    staging_schema_owner => 'SPA');
    END;
    /

    11:21:16 LUNARSPA@ lunardb> select NAME,OWNER,CREATED,STATEMENT_COUNT FROM DBA_SQLSET;

    NAME OWNER CREATED STATEMENT_COUNT
    ------------------------------ ------------------------------ ------------------- ---------------
    Lunar_11204STS_LUNAR LUNARSPA 2015-04-19 11:19:04 6005

    Elapsed: 00:00:00.01
    11:21:19 LUNARSPA@ lunardb>
    至此,SPA在新库的数据已经准备完毕,可以开始生成SPA报告了。
    常见报告的就提步骤如下:
    1)创建SPA任务

    11:33:10 LUNARSPA@ lunardb> exec :sname := 'Lunar_11204STS_GPS';
    exec :tname := 'SPA_LUNARTEST1';
    PL/SQL procedure successfully completed.

    Elapsed: 00:00:00.01
    11:33:10 LUNARSPA@ lunardb>

    PL/SQL procedure successfully completed.

    Elapsed: 00:00:00.00
    11:33:10 LUNARSPA@ lunardb> exec :tname := DBMS_SQLPA.CREATE_ANALYSIS_TASK(sqlset_name => :sname, task_name => :tname);

    PL/SQL procedure successfully completed.

    Elapsed: 00:00:00.19
    11:33:10 LUNARSPA@ lunardb>
    2)生成11.2.0.1的SPA Trail,采用STS转化方式

    begin
    DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(
    task_name => 'SPA_LUNARTEST1',
    execution_type => 'CONVERT SQLSET',
    execution_name => 'CONVERT_11204G');
    end;
    /

    3)在11.2.0.4中测试执行,从性能数据生成SPA trial
    begin
    DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(
    task_name => 'SPA_LUNARTEST1',
    execution_type => 'TEST EXECUTE',
    execution_name => 'EXEC_11204G');
    end;
    /
    5 执行比较任务(一般取Elapsed Time、CPU Time、Buffer Get等指标)

    begin
    DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(
    task_name => 'SPA_LUNARTEST1',
    execution_type => 'COMPARE PERFORMANCE',
    execution_name => 'Compare_elapsed_time',
    execution_params => dbms_advisor.arglist('execution_name1', 'CONVERT_11204G', 'execution_name2', 'EXEC_11204G', 'comparison_metric', 'elapsed_time') );
    end;
    /

    begin
    DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(
    task_name => 'SPA_LUNARTEST1',
    execution_type => 'COMPARE PERFORMANCE',
    execution_name => 'Compare_CPU_time',
    execution_params => dbms_advisor.arglist('execution_name1', 'CONVERT_11204G', 'execution_name2', 'EXEC_11204G', 'comparison_metric', 'CPU_TIME') );
    end;
    /

    begin
    DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(
    task_name => 'SPA_LUNARTEST1',
    execution_type => 'COMPARE PERFORMANCE',
    execution_name => 'Compare_BUFFER_GETS_time',
    execution_params => dbms_advisor.arglist('execution_name1', 'CONVERT_11204G', 'execution_name2', 'EXEC_11204G', 'comparison_metric', 'BUFFER_GETS') );
    end;
    /
    6 生成SPA报告

    spool spa_report_elapsed_time.html
    SELECT dbms_sqlpa.report_analysis_task('SPA_LUNARTEST1', 'HTML', 'ALL','ALL', execution_name=>'Compare_elapsed_time',top_sql=>500) FROM dual;
    spool off;

    spool spa_report_CPU_time.html
    SELECT dbms_sqlpa.report_analysis_task('SPA_LUNARTEST1', 'HTML', 'ALL','ALL', execution_name=>'Compare_CPU_time',top_sql=>500) FROM dual;
    spool off;


    spool spa_report_buffer_time.html
    SELECT dbms_sqlpa.report_analysis_task('SPA_LUNARTEST1','HTML','ALL','ALL', execution_name=>'Compare_BUFFER_GETS_time',top_sql=>500) FROM dual;
    spool off;

    spool spa_report_elapsed_time_regressed.html
    SELECT dbms_sqlpa.report_analysis_task('SPA_LUNARTEST1', 'HTML', 'REGRESSED','ALL', execution_name=>'Compare_elapsed_time',top_sql=>500) FROM dual;
    spool off;

    spool spa_report_CPU_time_regressed.html
    SELECT dbms_sqlpa.report_analysis_task('SPA_LUNARTEST1', 'HTML', 'REGRESSED','ALL', execution_name=>'Compare_CPU_time',top_sql=>500) FROM dual;
    spool off;


    spool spa_report_buffer_time_regressed.html
    SELECT dbms_sqlpa.report_analysis_task('SPA_LUNARTEST1','HTML','REGRESSED','ALL', execution_name=>'Compare_BUFFER_GETS_time',top_sql=>500) FROM dual;
    spool off;


    spool spa_report_errors.html
    SELECT dbms_sqlpa.report_analysis_task('SPA_LUNARTEST1', 'HTML', 'errors','summary') FROM dual;
    spool off;


    spool spa_report_unsupport.html
    SELECT dbms_sqlpa.report_analysis_task('SPA_LUNARTEST1', 'HTML', 'unsupported','all') FROM dual;
    spool off;
    生成的报告一般如下:

    -rwxrwxrwx 1 oracle oracle 1850 Apr 19 21:33 report_spa.sh
    -rw-rw-r-- 1 oracle oracle 8498134 Apr 19 21:37 spa_report_elapsed_time.html
    -rw-rw-r-- 1 oracle oracle 8954773 Apr 19 21:41 spa_report_CPU_time.html
    -rw-rw-r-- 1 oracle oracle 7941640 Apr 19 21:44 spa_report_buffer_time.html
    -rw-rw-r-- 1 oracle oracle 38933 Apr 19 21:44 spa_report_elapsed_time_regressed.html
    -rw-rw-r-- 1 oracle oracle 61982 Apr 19 21:44 spa_report_CPU_time_regressed.html
    -rw-rw-r-- 1 oracle oracle 28886 Apr 19 21:44 spa_report_buffer_time_regressed.html
    -rw-rw-r-- 1 oracle oracle 15537 Apr 19 21:44 spa_report_errors.html
    -rw-rw-r-- 1 oracle oracle 58703 Apr 19 21:44 spa_report_unsupport.html
    -rw-rw-r-- 1 oracle oracle 18608938 Apr 19 21:44 report_spa.log
    [oracle@lunardb tmp]$

    ############https://www.databasejournal.com/img/2008/02/jsc_Oracle_11g_SQL_Plan_Management_Listing2.html#List0201

    /*
    || Oracle 11g SQL Plan Management Listing 2
    ||
    || Demonstrates Oracle 11g SQL Plan Management (SPM) advanced techniques,
    || including:
    || - Capturing SQL Plan Baselines via manual methods with DBMS_SPM
    || - Transferring captured SQL Plan Baselines between Oracle 10g and 11g databases
    ||   to "pre-seed" the SQL Management Baseline (SMB) with the most optimal execution
    ||   plans before an upgrade of an Oracle 10g database to Oracle 11g
    || - Transferring captured SQL Plan Baselines between test and production environments
    ||   to "pre-seed" the SQL Management Baseline (SMB) with the most typical execution 
    ||   plans prior to deployment of a brand-new application
    || - Dropping existing SQL Plan Baselines from the SMB via manual methods
    ||
    || Author: Jim Czuprynski
    ||
    || Usage Notes:
    || These examples are provided to demonstrate various features of Oracle 11g
    || SQL Plan Management features, and they should be carefully proofread
    || before executing them against any existing Oracle database(s) to avoid
    || potential damage!
    */
    
    /*  
    || Listing 2.1:
    || Create and prepare to populate a SQL Tuning Set (STS)
    || for selected SQL statements. Note that this STS will capture
    || all SQL statements which are executed by the LDGN user account
    || within a 5-minute period, and Oracle will check every 5 seconds
    || for any new statements
    */
    
    BEGIN
        DBMS_SQLTUNE.DROP_SQLSET(
            sqlset_name => 'STS_SPM_200'
        );
    END;
    
    @SPM_2_1.sql;
    /
    BEGIN
        DBMS_SQLTUNE.CREATE_SQLSET(
            sqlset_name => 'STS_SPM_200'
        );
        DBMS_SQLTUNE.CAPTURE_CURSOR_CACHE_SQLSET(                         
             sqlset_name => 'STS_SPM_200'
            ,basic_filter=> q'#sql_text LIKE '%SPM_2_1%' AND parsing_schema_name = 'LDGN'#'
            ,time_limit  => 300
            ,repeat_interval => 5
        ); 
    END;
    /
    
    /*  
    || Listing 2.2:
    || "Packing up" and exporting the Oracle 10gR2 SQL Tuning Set prior to
    || its transport to Oracle 11g
    */
    
    -----
    -- Create a staging table to hold the SQL Tuning Set statements just created,
    -- and then "pack up" (i.e. populate) the staging table
    -----
    DROP TABLE ldgn.sts_staging PURGE;
    BEGIN
        DBMS_SQLTUNE.CREATE_STGTAB_SQLSET(
             table_name => 'STS_STAGING'
            ,schema_name => 'LDGN'
            ,tablespace_name => 'USERS'
        );
        DBMS_SQLTUNE.PACK_STGTAB_SQLSET(
             sqlset_name => 'STS_SPM_200'
            ,sqlset_owner => 'SYS'
            ,staging_table_name => 'STS_STAGING'
            ,staging_schema_owner => 'LDGN'
        );
    END;
    /
    
    -----
    -- Invoke DataPump Export to export the table that contains the staged 
    -- SQL Tuning Set statements
    -----
    rm -f /u01/app/oracle/product/10.2.0/db_1/rdbms/log/*.log
    rm -f /u01/app/oracle/product/10.2.0/db_1/rdbms/log/*.dmp
    expdp system/oracle PARFILE=DumpStagingTable.dpectl
    
    #####
    # Contents of DumpStagingTable.dpectl parameter file:
    #####
    JOB_NAME=DumpStagingTable
    DIRECTORY=DATA_PUMP_DIR
    DUMPFILE=LDGN_STS_Staging.dmp
    SCHEMAS=LDGN
    
    >>> Results:
    
    Export: Release 10.2.0.1.0 - Production on Monday, 18 February, 2008 19:03:57
    Copyright (c) 2003, 2005, Oracle.  All rights reserved.
    Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
    With the Partitioning, OLAP and Data Mining options
    Starting "SYSTEM"."DUMPSTAGINGTABLE":  system/******** PARFILE=DumpStagingTable.dpectl 
    Estimate in progress using BLOCKS method...
    Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
    Total estimation using BLOCKS method: 576 KB
    Processing object type SCHEMA_EXPORT/USER
    Processing object type SCHEMA_EXPORT/SYSTEM_GRANT
    Processing object type SCHEMA_EXPORT/ROLE_GRANT
    Processing object type SCHEMA_EXPORT/DEFAULT_ROLE
    Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
    Processing object type SCHEMA_EXPORT/TABLE/TABLE
    Processing object type SCHEMA_EXPORT/TABLE/INDEX/INDEX
    . . exported "LDGN"."STS_STAGING"                        22.67 KB       8 rows
    . . exported "LDGN"."STS_STAGING_CPLANS"                 35.35 KB      25 rows
    . . exported "LDGN"."STS_STAGING_CBINDS"                 9.476 KB       0 rows
    . . exported "LDGN"."PLAN_TABLE"                             0 KB       0 rows
    Master table "SYSTEM"."DUMPSTAGINGTABLE" successfully loaded/unloaded
    ******************************************************************************
    Dump file set for SYSTEM.DUMPSTAGINGTABLE is:
      /u01/app/oracle/product/10.2.0/db_1/rdbms/log/LDGN_STS_Staging.dmp
    Job "SYSTEM"."DUMPSTAGINGTABLE" successfully completed at 19:05:21
    
    /* 
    || Listing 2.3:
    || Transporting, importing, and "unpacking" the staged Oracle 10gR2 SQL Tuning
    || Set on the target Oracle 11g database
    */
    
    -----
    -- Invoke DataPump Import to import the table that contains the staged 
    -- SQL Tuning Set statements. Note that the default action of SKIPping
    -- a table if it already exists has been overridden by supplying a value
    -- of REPLACE for parameter TABLE_EXISTS_ACTION.
    -----
    impdp system/oracle PARFILE=LoadStagingTable.dpictl
    
    #####
    # Contents of LoadStagingTable.dpictl parameter file:
    #####
    JOB_NAME=LoadStagingTable
    DIRECTORY=DATA_PUMP_DIR
    DUMPFILE=LDGN_STS_Staging.dmp
    TABLE_EXISTS_ACTION=REPLACE
    
    >>> Results of DataPump Import operation:
    
    Import: Release 11.1.0.6.0 - Production on Monday, 18 February, 2008 19:09:29
    Copyright (c) 2003, 2007, Oracle.  All rights reserved.
    Connected to: Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production
    With the Partitioning, OLAP, Data Mining and Real Application Testing options
    Master table "SYSTEM"."LOADSTAGINGTABLE" successfully loaded/unloaded
    Starting "SYSTEM"."LOADSTAGINGTABLE":  system/******** PARFILE=LoadStagingTable.dpictl 
    Processing object type SCHEMA_EXPORT/USER
    ORA-31684: Object type USER:"LDGN" already exists
    Processing object type SCHEMA_EXPORT/SYSTEM_GRANT
    Processing object type SCHEMA_EXPORT/ROLE_GRANT
    Processing object type SCHEMA_EXPORT/DEFAULT_ROLE
    Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
    Processing object type SCHEMA_EXPORT/TABLE/TABLE
    Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
    . . imported "LDGN"."STS_STAGING"                        22.67 KB       8 rows
    . . imported "LDGN"."STS_STAGING_CPLANS"                 35.35 KB      25 rows
    . . imported "LDGN"."STS_STAGING_CBINDS"                 9.476 KB       0 rows
    . . imported "LDGN"."PLAN_TABLE"                             0 KB       0 rows
    Processing object type SCHEMA_EXPORT/TABLE/INDEX/INDEX
    Job "SYSTEM"."LOADSTAGINGTABLE" completed with 1 error(s) at 19:11:07
    
    -----
    -- Accept the SQL Tuning Set statements from the imported staging table
    -- into the Oracle 11gR1 database
    -----
    BEGIN
        DBMS_SQLTUNE.DROP_SQLSET(
            sqlset_name => 'STS_SPM_200'
        );
    END;
    /
    BEGIN
        DBMS_SQLTUNE.UNPACK_STGTAB_SQLSET(
             sqlset_name => 'STS_SPM_200'
            ,sqlset_owner => 'SYS'
            ,replace => TRUE
            ,staging_table_name => 'STS_STAGING'
            ,staging_schema_owner => 'LDGN'
        );
    END;
    /
    
    ----- 
    -- Listing 2.4:
    -- Prove that the SQL Plan Baselines loaded into the SMB via manual methods are
    -- actually being utilized by executing EXPLAIN PLANs against each statement from the
    -- target Oracle 11g database
    -----
    
    SQL> EXPLAIN PLAN FOR
      2  SELECT /*SPM_2_1.1*/
      3       CTY.country_total_id
      4      ,PR.promo_total_id
      5      ,COUNT(S.amount_sold)
      6      ,SUM(S.amount_sold)
      7      ,SUM(S.quantity_sold)
      8    FROM
      9       sh.sales S
     10      ,sh.customers C
     11      ,sh.countries CTY
     12      ,sh.promotions PR
     13   WHERE S.cust_id = C.cust_id
     14     AND C.country_id = CTY.country_id
     15     AND S.promo_id = PR.promo_id
     16   GROUP BY
     17       CTY.country_total_id
     18      ,PR.promo_total_id
     19  ;
    
    Explained.
    
    SQL> SELECT *
      2    FROM TABLE(DBMS_XPLAN.DISPLAY('PLAN_TABLE',NULL,'+NOTE'))
      3  ;
    
    Plan hash value: 491136032                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                    
    --------------------------------------------------------------------------------------------------------------                                                                                                                                                  
    | Id  | Operation               | Name       | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |                                                                                                                                                  
    --------------------------------------------------------------------------------------------------------------                                                                                                                                                  
    |   0 | SELECT STATEMENT        |            |     1 |    44 |       |  2325   (5)| 00:00:28 |       |       |                                                                                                                                                  
    |   1 |  HASH GROUP BY          |            |     1 |    44 |       |  2325   (5)| 00:00:28 |       |       |                                                                                                                                                  
    |*  2 |   HASH JOIN             |            |   918K|    38M|       |  2270   (3)| 00:00:28 |       |       |                                                                                                                                                  
    |   3 |    TABLE ACCESS FULL    | PROMOTIONS |   503 |  3521 |       |    17   (0)| 00:00:01 |       |       |                                                                                                                                                  
    |*  4 |    HASH JOIN            |            |   918K|    32M|       |  2246   (2)| 00:00:27 |       |       |                                                                                                                                                  
    |   5 |     TABLE ACCESS FULL   | COUNTRIES  |    23 |   230 |       |     3   (0)| 00:00:01 |       |       |                                                                                                                                                  
    |*  6 |     HASH JOIN           |            |   918K|    23M|  1200K|  2236   (2)| 00:00:27 |       |       |                                                                                                                                                  
    |   7 |      TABLE ACCESS FULL  | CUSTOMERS  | 55500 |   541K|       |   406   (1)| 00:00:05 |       |       |                                                                                                                                                  
    |   8 |      PARTITION RANGE ALL|            |   918K|    14M|       |   498   (4)| 00:00:06 |     1 |    28 |                                                                                                                                                  
    |   9 |       TABLE ACCESS FULL | SALES      |   918K|    14M|       |   498   (4)| 00:00:06 |     1 |    28 |                                                                                                                                                  
    --------------------------------------------------------------------------------------------------------------                                                                                                                                                  
                                                                                                                                                                                                                                                                    
    Predicate Information (identified by operation id):                                                                                                                                                                                                             
    ---------------------------------------------------                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                    
       2 - access("S"."PROMO_ID"="PR"."PROMO_ID")                                                                                                                                                                                                                   
       4 - access("C"."COUNTRY_ID"="CTY"."COUNTRY_ID")                                                                                                                                                                                                              
       6 - access("S"."CUST_ID"="C"."CUST_ID")                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                    
    Note                                                                                                                                                                                                                                                            
    -----                                                                                                                                                                                                                                                           
       - SQL plan baseline "SYS_SQL_PLAN_587c0594825d2e47" used for this statement                                                                                                                                                                                  
    
    27 rows selected.
    
    SQL> 
    SQL> EXPLAIN PLAN FOR
      2  SELECT /*SPM_2_1.2*/
      3       CTY.country_id
      4      ,CTY.country_subregion_id
      5      ,CTY.country_region_id
      6      ,CTY.country_total_id
      7      ,PR.promo_total_id
      8      ,COUNT(S.amount_sold)
      9      ,SUM(S.amount_sold)
     10      ,SUM(S.quantity_sold)
     11    FROM
     12       sh.sales S
     13      ,sh.customers C
     14      ,sh.countries CTY
     15      ,sh.promotions PR
     16   WHERE S.cust_id = C.cust_id
     17     AND C.country_id = CTY.country_id
     18     AND S.promo_id = PR.promo_id
     19  GROUP BY
     20       CTY.country_id
     21      ,CTY.country_subregion_id
     22      ,CTY.country_region_id
     23      ,CTY.country_total_id
     24      ,PR.promo_total_id
     25  ;
    
    Explained.
    
    SQL> SELECT *
      2    FROM TABLE(DBMS_XPLAN.DISPLAY('PLAN_TABLE',NULL,'+NOTE'))
      3  ;
    
    Plan hash value: 491136032                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                    
    --------------------------------------------------------------------------------------------------------------                                                                                                                                                  
    | Id  | Operation               | Name       | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |                                                                                                                                                  
    --------------------------------------------------------------------------------------------------------------                                                                                                                                                  
    |   0 | SELECT STATEMENT        |            |   228 | 12312 |       |  2325   (5)| 00:00:28 |       |       |                                                                                                                                                  
    |   1 |  HASH GROUP BY          |            |   228 | 12312 |       |  2325   (5)| 00:00:28 |       |       |                                                                                                                                                  
    |*  2 |   HASH JOIN             |            |   918K|    47M|       |  2270   (3)| 00:00:28 |       |       |                                                                                                                                                  
    |   3 |    TABLE ACCESS FULL    | PROMOTIONS |   503 |  3521 |       |    17   (0)| 00:00:01 |       |       |                                                                                                                                                  
    |*  4 |    HASH JOIN            |            |   918K|    41M|       |  2246   (2)| 00:00:27 |       |       |                                                                                                                                                  
    |   5 |     TABLE ACCESS FULL   | COUNTRIES  |    23 |   460 |       |     3   (0)| 00:00:01 |       |       |                                                                                                                                                  
    |*  6 |     HASH JOIN           |            |   918K|    23M|  1200K|  2236   (2)| 00:00:27 |       |       |                                                                                                                                                  
    |   7 |      TABLE ACCESS FULL  | CUSTOMERS  | 55500 |   541K|       |   406   (1)| 00:00:05 |       |       |                                                                                                                                                  
    |   8 |      PARTITION RANGE ALL|            |   918K|    14M|       |   498   (4)| 00:00:06 |     1 |    28 |                                                                                                                                                  
    |   9 |       TABLE ACCESS FULL | SALES      |   918K|    14M|       |   498   (4)| 00:00:06 |     1 |    28 |                                                                                                                                                  
    --------------------------------------------------------------------------------------------------------------                                                                                                                                                  
                                                                                                                                                                                                                                                                    
    Predicate Information (identified by operation id):                                                                                                                                                                                                             
    ---------------------------------------------------                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                    
       2 - access("S"."PROMO_ID"="PR"."PROMO_ID")                                                                                                                                                                                                                   
       4 - access("C"."COUNTRY_ID"="CTY"."COUNTRY_ID")                                                                                                                                                                                                              
       6 - access("S"."CUST_ID"="C"."CUST_ID")                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                    
    Note                                                                                                                                                                                                                                                            
    -----                                                                                                                                                                                                                                                           
       - SQL plan baseline "SYS_SQL_PLAN_54f64750825d2e47" used for this statement                                                                                                                                                                                  
    
    27 rows selected.
    
    SQL> 
    SQL> EXPLAIN PLAN FOR
      2  SELECT /*SPM_2_1.3*/
      3       CTY.country_total_id
      4      ,P.prod_id
      5      ,P.prod_subcategory_id
      6      ,P.prod_category_id
      7      ,P.prod_total_id
      8      ,CH.channel_id
      9      ,CH.channel_class_id
     10      ,CH.channel_total_id
     11      ,PR.promo_total_id
     12      ,COUNT(S.amount_sold)
     13      ,SUM(S.amount_sold)
     14      ,SUM(S.quantity_sold)
     15    FROM
     16       sh.sales S
     17      ,sh.customers C
     18      ,sh.countries CTY
     19      ,sh.products P
     20      ,sh.channels CH
     21      ,sh.promotions PR
     22   WHERE S.cust_id = C.cust_id
     23     AND C.country_id = CTY.country_id
     24     AND S.prod_id = P.prod_id
     25     AND S.channel_id = CH.channel_id
     26     AND S.promo_id = PR.promo_id
     27   GROUP BY
     28       CTY.country_total_id
     29      ,P.prod_id
     30      ,P.prod_subcategory_id
     31      ,P.prod_category_id
     32      ,P.prod_total_id
     33      ,CH.channel_id
     34      ,CH.channel_class_id
     35      ,CH.channel_total_id
     36      ,PR.promo_total_id
     37  ;
    
    Explained.
    
    SQL> SELECT *
      2    FROM TABLE(DBMS_XPLAN.DISPLAY('PLAN_TABLE',NULL,'+NOTE'))
      3  ;
    
    Plan hash value: 2634317694                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                    
    ----------------------------------------------------------------------------------------------------------------                                                                                                                                                
    | Id  | Operation                 | Name       | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |                                                                                                                                                
    ----------------------------------------------------------------------------------------------------------------                                                                                                                                                
    |   0 | SELECT STATEMENT          |            |  5940 |   435K|       |  8393   (2)| 00:01:41 |       |       |                                                                                                                                                
    |   1 |  HASH GROUP BY            |            |  5940 |   435K|    74M|  8393   (2)| 00:01:41 |       |       |                                                                                                                                                
    |*  2 |   HASH JOIN               |            |   918K|    65M|       |  2593   (3)| 00:00:32 |       |       |                                                                                                                                                
    |   3 |    TABLE ACCESS FULL      | PROMOTIONS |   503 |  3521 |       |    17   (0)| 00:00:01 |       |       |                                                                                                                                                
    |*  4 |    HASH JOIN              |            |   918K|    59M|       |  2569   (3)| 00:00:31 |       |       |                                                                                                                                                
    |   5 |     TABLE ACCESS FULL     | PRODUCTS   |    72 |  1080 |       |     3   (0)| 00:00:01 |       |       |                                                                                                                                                
    |*  6 |     HASH JOIN             |            |   918K|    46M|       |  2560   (2)| 00:00:31 |       |       |                                                                                                                                                
    |   7 |      TABLE ACCESS FULL    | COUNTRIES  |    23 |   230 |       |     3   (0)| 00:00:01 |       |       |                                                                                                                                                
    |*  8 |      HASH JOIN            |            |   918K|    37M|       |  2550   (2)| 00:00:31 |       |       |                                                                                                                                                
    |   9 |       TABLE ACCESS FULL   | CHANNELS   |     5 |    45 |       |     3   (0)| 00:00:01 |       |       |                                                                                                                                                
    |* 10 |       HASH JOIN           |            |   918K|    29M|  1200K|  2541   (2)| 00:00:31 |       |       |                                                                                                                                                
    |  11 |        TABLE ACCESS FULL  | CUSTOMERS  | 55500 |   541K|       |   406   (1)| 00:00:05 |       |       |                                                                                                                                                
    |  12 |        PARTITION RANGE ALL|            |   918K|    21M|       |   498   (4)| 00:00:06 |     1 |    28 |                                                                                                                                                
    |  13 |         TABLE ACCESS FULL | SALES      |   918K|    21M|       |   498   (4)| 00:00:06 |     1 |    28 |                                                                                                                                                
    ----------------------------------------------------------------------------------------------------------------                                                                                                                                                
                                                                                                                                                                                                                                                                    
    Predicate Information (identified by operation id):                                                                                                                                                                                                             
    ---------------------------------------------------                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                    
       2 - access("S"."PROMO_ID"="PR"."PROMO_ID")                                                                                                                                                                                                                   
       4 - access("S"."PROD_ID"="P"."PROD_ID")                                                                                                                                                                                                                      
       6 - access("C"."COUNTRY_ID"="CTY"."COUNTRY_ID")                                                                                                                                                                                                              
       8 - access("S"."CHANNEL_ID"="CH"."CHANNEL_ID")                                                                                                                                                                                                               
      10 - access("S"."CUST_ID"="C"."CUST_ID")                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                    
    Note                                                                                                                                                                                                                                                            
    -----                                                                                                                                                                                                                                                           
       - SQL plan baseline "SYS_SQL_PLAN_8ec1a5862d9d97db" used for this statement                                                                                                                                                                                  
    
    33 rows selected.
    
    SQL> 
    SQL> EXPLAIN PLAN FOR
      2  SELECT /*SPM_2_1.4*/
      3       CTY.country_total_id
      4      ,P.prod_category_id
      5      ,P.prod_total_id
      6      ,CH.channel_id
      7      ,CH.channel_class_id
      8      ,CH.channel_total_id
      9      ,PR.promo_total_id
     10      ,COUNT(S.amount_sold)
     11      ,SUM(S.amount_sold)
     12      ,SUM(S.quantity_sold)
     13    FROM
     14       sh.sales S
     15      ,sh.customers C
     16      ,sh.countries CTY
     17      ,sh.products P
     18      ,sh.channels CH
     19      ,sh.promotions PR
     20   WHERE S.cust_id = C.cust_id
     21     AND C.country_id = CTY.country_id
     22     AND S.prod_id = P.prod_id
     23     AND S.channel_id = CH.channel_id
     24     AND S.promo_id = PR.promo_id
     25   GROUP BY
     26       CTY.country_total_id
     27      ,P.prod_category_id
     28      ,P.prod_total_id
     29      ,CH.channel_id
     30      ,CH.channel_class_id
     31      ,CH.channel_total_id
     32      ,PR.promo_total_id
     33  ;
    
    Explained.
    
    SQL> SELECT *
      2    FROM TABLE(DBMS_XPLAN.DISPLAY('PLAN_TABLE',NULL,'+NOTE'))
      3  ;
    
    Plan hash value: 2634317694                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                    
    ----------------------------------------------------------------------------------------------------------------                                                                                                                                                
    | Id  | Operation                 | Name       | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |                                                                                                                                                
    ----------------------------------------------------------------------------------------------------------------                                                                                                                                                
    |   0 | SELECT STATEMENT          |            |     8 |   568 |       |  2648   (5)| 00:00:32 |       |       |                                                                                                                                                
    |   1 |  HASH GROUP BY            |            |     8 |   568 |       |  2648   (5)| 00:00:32 |       |       |                                                                                                                                                
    |*  2 |   HASH JOIN               |            |   918K|    62M|       |  2593   (3)| 00:00:32 |       |       |                                                                                                                                                
    |   3 |    TABLE ACCESS FULL      | PROMOTIONS |   503 |  3521 |       |    17   (0)| 00:00:01 |       |       |                                                                                                                                                
    |*  4 |    HASH JOIN              |            |   918K|    56M|       |  2569   (3)| 00:00:31 |       |       |                                                                                                                                                
    |   5 |     TABLE ACCESS FULL     | PRODUCTS   |    72 |   792 |       |     3   (0)| 00:00:01 |       |       |                                                                                                                                                
    |*  6 |     HASH JOIN             |            |   918K|    46M|       |  2560   (2)| 00:00:31 |       |       |                                                                                                                                                
    |   7 |      TABLE ACCESS FULL    | COUNTRIES  |    23 |   230 |       |     3   (0)| 00:00:01 |       |       |                                                                                                                                                
    |*  8 |      HASH JOIN            |            |   918K|    37M|       |  2550   (2)| 00:00:31 |       |       |                                                                                                                                                
    |   9 |       TABLE ACCESS FULL   | CHANNELS   |     5 |    45 |       |     3   (0)| 00:00:01 |       |       |                                                                                                                                                
    |* 10 |       HASH JOIN           |            |   918K|    29M|  1200K|  2541   (2)| 00:00:31 |       |       |                                                                                                                                                
    |  11 |        TABLE ACCESS FULL  | CUSTOMERS  | 55500 |   541K|       |   406   (1)| 00:00:05 |       |       |                                                                                                                                                
    |  12 |        PARTITION RANGE ALL|            |   918K|    21M|       |   498   (4)| 00:00:06 |     1 |    28 |                                                                                                                                                
    |  13 |         TABLE ACCESS FULL | SALES      |   918K|    21M|       |   498   (4)| 00:00:06 |     1 |    28 |                                                                                                                                                
    ----------------------------------------------------------------------------------------------------------------                                                                                                                                                
                                                                                                                                                                                                                                                                    
    Predicate Information (identified by operation id):                                                                                                                                                                                                             
    ---------------------------------------------------                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                    
       2 - access("S"."PROMO_ID"="PR"."PROMO_ID")                                                                                                                                                                                                                   
       4 - access("S"."PROD_ID"="P"."PROD_ID")                                                                                                                                                                                                                      
       6 - access("C"."COUNTRY_ID"="CTY"."COUNTRY_ID")                                                                                                                                                                                                              
       8 - access("S"."CHANNEL_ID"="CH"."CHANNEL_ID")                                                                                                                                                                                                               
      10 - access("S"."CUST_ID"="C"."CUST_ID")                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                    
    Note                                                                                                                                                                                                                                                            
    -----                                                                                                                                                                                                                                                           
       - SQL plan baseline "SYS_SQL_PLAN_96f761da2d9d97db" used for this statement                                                                                                                                                                                  
    
    33 rows selected.
    
    SQL> 
    SQL> EXPLAIN PLAN FOR
      2  SELECT /*SPM_2_1.5*/
      3       CTY.country_id
      4      ,CTY.country_subregion_id
      5      ,CTY.country_region_id
      6      ,CTY.country_total_id
      7      ,P.prod_id
      8      ,P.prod_subcategory_id
      9      ,P.prod_category_id
     10      ,P.prod_total_id
     11      ,CH.channel_id
     12      ,CH.channel_class_id
     13      ,CH.channel_total_id
     14      ,PR.promo_total_id
     15      ,COUNT(S.amount_sold)
     16      ,SUM(S.amount_sold)
     17      ,SUM(S.quantity_sold)
     18    FROM
     19       sh.sales S
     20      ,sh.customers C
     21      ,sh.countries CTY
     22      ,sh.products P
     23      ,sh.channels CH
     24      ,sh.promotions PR
     25   WHERE S.cust_id = C.cust_id
     26     AND C.country_id = CTY.country_id
     27     AND S.prod_id = P.prod_id
     28     AND S.channel_id = CH.channel_id
     29     AND S.promo_id = PR.promo_id
     30   GROUP BY
     31       CTY.country_id
     32      ,CTY.country_subregion_id
     33      ,CTY.country_region_id
     34      ,CTY.country_total_id
     35      ,P.prod_id
     36      ,P.prod_subcategory_id
     37      ,P.prod_category_id
     38      ,P.prod_total_id
     39      ,CH.channel_id
     40      ,CH.channel_class_id
     41      ,CH.channel_total_id
     42      ,PR.promo_total_id
     43  ;
    
    Explained.
    
    SQL> SELECT *
      2    FROM TABLE(DBMS_XPLAN.DISPLAY('PLAN_TABLE',NULL,'+NOTE'))
      3  ;
    
    Plan hash value: 2634317694                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                    
    ----------------------------------------------------------------------------------------------------------------                                                                                                                                                
    | Id  | Operation                 | Name       | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |                                                                                                                                                
    ----------------------------------------------------------------------------------------------------------------                                                                                                                                                
    |   0 | SELECT STATEMENT          |            |   918K|    74M|       | 20707   (1)| 00:04:09 |       |       |                                                                                                                                                
    |   1 |  HASH GROUP BY            |            |   918K|    74M|   168M| 20707   (1)| 00:04:09 |       |       |                                                                                                                                                
    |*  2 |   HASH JOIN               |            |   918K|    74M|       |  2593   (3)| 00:00:32 |       |       |                                                                                                                                                
    |   3 |    TABLE ACCESS FULL      | PROMOTIONS |   503 |  3521 |       |    17   (0)| 00:00:01 |       |       |                                                                                                                                                
    |*  4 |    HASH JOIN              |            |   918K|    68M|       |  2569   (3)| 00:00:31 |       |       |                                                                                                                                                
    |   5 |     TABLE ACCESS FULL     | PRODUCTS   |    72 |  1080 |       |     3   (0)| 00:00:01 |       |       |                                                                                                                                                
    |*  6 |     HASH JOIN             |            |   918K|    55M|       |  2560   (2)| 00:00:31 |       |       |                                                                                                                                                
    |   7 |      TABLE ACCESS FULL    | COUNTRIES  |    23 |   460 |       |     3   (0)| 00:00:01 |       |       |                                                                                                                                                
    |*  8 |      HASH JOIN            |            |   918K|    37M|       |  2550   (2)| 00:00:31 |       |       |                                                                                                                                                
    |   9 |       TABLE ACCESS FULL   | CHANNELS   |     5 |    45 |       |     3   (0)| 00:00:01 |       |       |                                                                                                                                                
    |* 10 |       HASH JOIN           |            |   918K|    29M|  1200K|  2541   (2)| 00:00:31 |       |       |                                                                                                                                                
    |  11 |        TABLE ACCESS FULL  | CUSTOMERS  | 55500 |   541K|       |   406   (1)| 00:00:05 |       |       |                                                                                                                                                
    |  12 |        PARTITION RANGE ALL|            |   918K|    21M|       |   498   (4)| 00:00:06 |     1 |    28 |                                                                                                                                                
    |  13 |         TABLE ACCESS FULL | SALES      |   918K|    21M|       |   498   (4)| 00:00:06 |     1 |    28 |                                                                                                                                                
    ----------------------------------------------------------------------------------------------------------------                                                                                                                                                
                                                                                                                                                                                                                                                                    
    Predicate Information (identified by operation id):                                                                                                                                                                                                             
    ---------------------------------------------------                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                    
       2 - access("S"."PROMO_ID"="PR"."PROMO_ID")                                                                                                                                                                                                                   
       4 - access("S"."PROD_ID"="P"."PROD_ID")                                                                                                                                                                                                                      
       6 - access("C"."COUNTRY_ID"="CTY"."COUNTRY_ID")                                                                                                                                                                                                              
       8 - access("S"."CHANNEL_ID"="CH"."CHANNEL_ID")                                                                                                                                                                                                               
      10 - access("S"."CUST_ID"="C"."CUST_ID")                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                    
    Note                                                                                                                                                                                                                                                            
    -----                                                                                                                                                                                                                                                           
       - SQL plan baseline "SYS_SQL_PLAN_816fca3a2d9d97db" used for this statement                                                                                                                                                                                  
    
    33 rows selected.
    
    
    /* 
    || Listing 2.5:
    || Prepare to deploy a simulated new application to the current Oracle 11g database.
    || Note that all SQL Plan Baselines that are currently tagged as SPM_2 statements
    || will first be purged from the SMB.
    */
    
    -----
    -- Clear all SQL Plan Baselines whose SQL text contains the tag "SPM_2"
    -----
    SET SERVEROUTPUT ON
    VARIABLE nRtnCode NUMBER;
    BEGIN
        :nRtnCode := 0;
        FOR r_SPMB IN (
    	SELECT sql_handle, plan_name
              FROM dba_sql_plan_baselines
             WHERE sql_text LIKE '%SPM_2%'
    	)
            LOOP
                :nRtnCode :=
        		DBMS_SPM.DROP_SQL_PLAN_BASELINE(r_SPMB.sql_handle, r_SPMB.plan_name);
    		DBMS_OUTPUT.PUT_LINE('Drop of SPBs for Handle ' || r_SPMB.sql_handle
                    || ' and Plan ' || r_SPMB.plan_name
                    || ' completed: RC = ' || :nRtnCode);
    		END LOOP;
    EXCEPTION
    	WHEN OTHERS THEN
    		DBMS_OUTPUT.PUT_LINE('Fatal error during cleanup of SQL Plan Baselines!');
        	ROLLBACK;
    END;
    /
    
    -----
    -- Run DDL commands to create the Sales Force Administration (SFA) schema
    -- and all related objects
    -----
    @SFA_Setup.sql;
    
    /* 
    || Listing 2.6:
    || Generate a SQL workload against the new application objects using six
    || queries tagged with a comment of SPM_2_2, and then capture the SQL Plan
    || Baselines into the SMB using DBMS_SPM.LOAD_PLANS_FROM CURSOR_CACHE
    */
    
    ALTER SYSTEM FLUSH SHARED_POOL;
    ALTER SYSTEM FLUSH BUFFER_CACHE;
    
    @SPM_2_2.sql;
    
    SET SERVEROUTPUT ON
    VARIABLE plans_cached NUMBER;
    BEGIN
        :plans_cached := 
            DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(
                 attribute_name => 'SQL_TEXT'
                ,attribute_value => '%SPM_2_2%'
                ,fixed => 'NO'
                ,enabled => 'YES'
            );
        DBMS_OUTPUT.PUT_LINE('>>> ' || :plans_cached || ' SQL statement(s) loaded from the cursor cache.');
    END;
    /
    
    /* 
    || Listing 2.7:
    || Staging, Packing, and Exporting SQL Plan Baselines
    */
    
    -----
    -- Create a SQL Plan Baseline staging table and then "pack" those SQL 
    -- Plan Baselines into a staging table
    -----
    BEGIN
        DBMS_SPM.CREATE_STGTAB_BASELINE (
             table_name => 'SPM_STAGING'
            ,table_owner => 'SFA'
            ,tablespace_name => 'EXAMPLE'
        );
    END;
    /
    
    SET SERVEROUTPUT ON
    VARIABLE plans_staged NUMBER;
    BEGIN
        :plans_staged :=
            DBMS_SPM.PACK_STGTAB_BASELINE (
                table_name => 'SPM_STAGING'
               ,table_owner => 'SFA'
               ,creator => 'SYS'
            );
        DBMS_OUTPUT.PUT_LINE('Total SQL Plan Baselines Staged: ' || :plans_staged);
    END;
    /
    
    -----
    -- Export SPM staging table via DataPump Export
    -----
    rm -f /u01/app/oracle/admin/orcl/dpdump/*.log
    rm -f /u01/app/oracle/admin/orcl/dpdump/*.dmp
    expdp system/oracle PARFILE=DumpStagedSPMs.dpectl
    
    #####
    # Contents of DumpStagedSPMs.dpectl parameter file:
    #####
    JOB_NAME=DumpStagedSPMs
    DIRECTORY=DATA_PUMP_DIR
    DUMPFILE=SFA_SPM_Staging.dmp
    TABLES=SFA.SPM_STAGING
    
    >>> Results:
    
    Export: Release 11.1.0.6.0 - Production on Tuesday, 19 February, 2008 9:28:34
    Copyright (c) 2003, 2007, Oracle.  All rights reserved.
    Connected to: Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production
    With the Partitioning, OLAP, Data Mining and Real Application Testing options
    Starting "SYSTEM"."DUMPSTAGEDSPMS":  system/******** PARFILE=DumpStagedSPMs.dpectl 
    Estimate in progress using BLOCKS method...
    Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
    Total estimation using BLOCKS method: 192 KB
    Processing object type TABLE_EXPORT/TABLE/TABLE
    . . exported "SFA"."SPM_STAGING"                         46.49 KB       6 rows
    Master table "SYSTEM"."DUMPSTAGEDSPMS" successfully loaded/unloaded
    ******************************************************************************
    Dump file set for SYSTEM.DUMPSTAGEDSPMS is:
      /u01/app/oracle/admin/orcl/dpdump/SFA_SPM_Staging.dmp
    Job "SYSTEM"."DUMPSTAGEDSPMS" successfully completed at 09:29:50
    
    /* 
    || Listing 2.8:
    || Importing and "unpacking" the staged Oracle 11g SQL Plan Baselines into
    || the target Oracle 11g database
    */
    
    -----
    -- Invoke DataPump Import to import the table that contains the staged 
    -- SQL Tuning Set statements. Note that the default action of SKIPping
    -- a table if it already exists has been overridden by supplying a value
    -- of REPLACE for parameter TABLE_EXISTS_ACTION.
    -----
    impdp system/oracle PARFILE=LoadStagedSPMs.dpictl
    
    #####
    # Contents of LoadStagedSPMs.dpictl parameter file:
    #####
    JOB_NAME=LoadStagedSPMs
    DIRECTORY=DATA_PUMP_DIR
    DUMPFILE=SFA_SPM_Staging.dmp
    TABLE_EXISTS_ACTION=REPLACE
    
    >>> Results of DataPump Import operation:
    
    Import: Release 11.1.0.6.0 - Production on Tuesday, 19 February, 2008 9:31:41
    Copyright (c) 2003, 2007, Oracle.  All rights reserved.
    Connected to: Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production
    With the Partitioning, OLAP, Data Mining and Real Application Testing options
    Master table "SYSTEM"."LOADSTAGEDSPMS" successfully loaded/unloaded
    Starting "SYSTEM"."LOADSTAGEDSPMS":  system/******** PARFILE=LoadStagedSPMs.dpictl 
    Processing object type TABLE_EXPORT/TABLE/TABLE
    Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
    . . imported "SFA"."SPM_STAGING"                         46.49 KB       6 rows
    Job "SYSTEM"."LOADSTAGEDSPMS" successfully completed at 09:31:52
    
    -----
    -- Clear all SQL Plan Baselines whose SQL text contains the tag "SPM_2"
    -----
    SET SERVEROUTPUT ON
    VARIABLE nRtnCode NUMBER;
    BEGIN
        :nRtnCode := 0;
        FOR r_SPMB IN (
    	SELECT sql_handle, plan_name
              FROM dba_sql_plan_baselines
             WHERE sql_text LIKE '%SPM_2%'
    	)
            LOOP
                :nRtnCode :=
        		DBMS_SPM.DROP_SQL_PLAN_BASELINE(r_SPMB.sql_handle, r_SPMB.plan_name);
    		DBMS_OUTPUT.PUT_LINE('Drop of SPBs for Handle ' || r_SPMB.sql_handle
                    || ' and Plan ' || r_SPMB.plan_name
                    || ' completed: RC = ' || :nRtnCode);
    		END LOOP;
    EXCEPTION
    	WHEN OTHERS THEN
    		DBMS_OUTPUT.PUT_LINE('Fatal error during cleanup of SQL Plan Baselines!');
        	ROLLBACK;
    END;
    /
    
    -----
    -- Now, "unpack" the SQL Plan Baselines staging table directly into the SMB
    -----
    SET SERVEROUTPUT ON
    VARIABLE plans_loaded NUMBER;
    BEGIN
        :plans_loaded :=
            DBMS_SPM.UNPACK_STGTAB_BASELINE (
                table_name => 'SPM_STAGING'
               ,table_owner => 'SFA'
               ,creator => 'SYS'
            );
        DBMS_OUTPUT.PUT_LINE('Total SQL Plan Baselines Loaded: ' || :plans_loaded);
    END;
    /
    
    /* 
    || Listing 2.9:
    || Show the current contents of the SQL Management Base
    */
    
    Tue Feb 19                                                                                                   page    1
                                                         Current SQL Plan Baselines
                                                       (From DBA_SQL_PLAN_BASELINES)
    
             SQL      Plan                                                 CBO Ena-           Auto Created     Last
    Creator  Handle   Name     SQL Text                  Origin           Cost bled Acpt Fixd Purg On          Executed
    -------- -------- -------- ------------------------- ------------ -------- ---- ---- ---- ---- ----------- -----------
    LDGN     68516a84 07e0351f SELECT /*SPM_1.1*/        AUTO-CAPTURE      757 YES  YES  NO   YES  2008-01-20  2008-01-20
                                    S.cust_id                                                      10:47:14    10:47:31
                                    ,C.cust_last_name
                                   ,S.prod_id
                                    ,P.pro
    
    LDGN     68516a84 ddc1fcd0 SELECT /*SPM_1.1*/        AUTO-CAPTURE     2388 YES  NO   NO   YES  2008-01-20
                                    S.cust_id                                                      11:04:03
                                    ,C.cust_last_name
                                   ,S.prod_id
                                    ,P.pro
    
    SYS      0047dfb5 e86f00e7 SELECT /*SPM_2_2.5*/      MANUAL-LOAD        13 YES  YES  NO   YES  2008-02-19
                                   SR.abbr                                                         09:32:42
                                  ,SD.abbr
                                  ,SUM(SH.quantity_sold)
    
    SYS      1e72d0bd dd777d18 SELECT /*SPM_2_2.4*/      MANUAL-LOAD        13 YES  YES  NO   YES  2008-02-19
                                   rgn_abbr                                                        09:32:42
                                  ,dst_abbr
                                  ,ter_abbr
                                  ,cust_id
    
    
    SYS      7f161ead bb24e20c SELECT /*SPM_2.2.2*/      MANUAL-LOAD       415 YES  YES  NO   YES  2008-02-19
                                     SR.abbr,                                                      09:32:42
                                     SD.abbr,
                                     SZ.geo_id,
    
    SYS      831c508c 3519879f SELECT /*SPM_2_2.3*/      MANUAL-LOAD        71 YES  YES  NO   YES  2008-02-19
                                   SR.abbr                                                         09:32:42
                                  ,SD.abbr
                                  ,SZ.geo_id
                                  ,C.cust_id
    
    
    SYS      9c7bbbfb 9d1c7b8e SELECT /*SPM_2.2.1*/      MANUAL-LOAD       921 YES  YES  NO   YES  2008-02-19
                                    C.cust_state_provinc                                           09:32:42
                               e
                                   ,SUM(sh.quantity_sold
                               )
    
    SYS      f6743c1d b197d40d SELECT /*SPM_2_2.6*/      MANUAL-LOAD        60 YES  YES  NO   YES  2008-02-19
                                   SR.abbr                                                         09:32:42
                                  ,SUM(SH.quantity_sold)
                                  ,AVG(SH.quant
    
    8 rows selected.
    

    ##############ref 3

    https://blog.yannickjaquier.com/oracle/sql-performance-analyzer.html

    SQL Performance Analyzer

    Preamble

    How to test and predict impact on your application of any system change ? What a difficult question for a developer/DBA and except comparing SQL statement by SQL statement there is no dedicated tool for this. With 11gR2 Oracle has released a new tool called SQL Performance Analyzer.

    Before going further it’s worth to mention that SQL Performance Analyzer (SPA) is included in Oracle Real Application Testing (RAT) Enterprise Edition paidoption.

    By system changes Oracle mean (not exhaustively):

    • Database upgrades.
    • Tuning changes.
    • Schema changes.
    • Statistics gathering.
    • Initialization parameter change
    • OS or hardware changes.

    Database upgrade is exactly what we will test in this blog post by simulating execution of a SQL statement in Oracle 9iR2 and then in 11gR2. Notice that same strategy can be applied to evaluate any initialization parameter, statistics (with pending statistics) changes.

    Test database of this blog post is Oracle Enterprise Edition 11.2.0.2.0 running on Red Hat Enterprise Linux Server release 5.6 (Tikanga).

    SQL Performance Analyzer testing

    Just to show one limitation of SPA, but not of SQL Tuning Set (STS) I’m choosing a sql_id that has multiple plan with following query:

    SQL> SELECT * FROM (SELECT sql_id,COUNT(DISTINCT plan_hash_value) FROM v$sql a
         WHERE EXISTS (SELECT sql_id, COUNT(*) FROM v$sql b WHERE a.sql_id=b.sql_id GROUP BY sql_id HAVING COUNT(*)>1)
         GROUP BY sql_id ORDER BY 2 DESC) WHERE rownum<=10;
     
    SQL_ID        COUNT(DISTINCTPLAN_HASH_VALUE)
    ------------- ------------------------------
    94rn6s4ba24wn                              5
    9j8p0n3104sdg                              4
    gv9varx8zfkq4                              4
    9wbvj5pud8t2f                              4
    20pm94kcsc31s                              3
    afrmyr507wu03                              3
    0tnssv00b0nyr                              2
    1ds1kuqzkr7kn                              2
    18hzyzu9945g4                              2
    1290sa2814wt2                              2
     
    10 ROWS selected.

    Let’s choose first one and create a STS with the five sql_id, plan_hash_value pairs:

    DECLARE
      cursor1 DBMS_SQLTUNE.SQLSET_CURSOR;
    BEGIN
      OPEN cursor1 FOR SELECT VALUE(p)
      FROM TABLE(DBMS_SQLTUNE.SELECT_CURSOR_CACHE('sql_id = ''94rn6s4ba24wn''')) p;
     
      DBMS_SQLTUNE.LOAD_SQLSET(sqlset_name => 'STS01', populate_cursor => cursor1);
    END;
    /
     
    PL/SQL PROCEDURE successfully completed.

    We easily see that one SQL statement has been added to our STS even if the sql_id has five distinct explain plan:

    SQL> SET lines 200
    SQL> col description FOR a30
    SQL> SELECT * FROM dba_sqlset;
     
            ID NAME                           OWNER                          DESCRIPTION                    CREATED   LAST_MODI STATEMENT_COUNT
    ---------- ------------------------------ ------------------------------ ------------------------------ --------- --------- ---------------
             1 STS01                          SYS                            STS FOR sql_id 94rn6s4ba24wn   17-NOV-11 17-NOV-11               1

    Now let’s create a SPA task and associate the STS with it:

    DECLARE
      task_name VARCHAR2(64);
      sts_task  VARCHAR2(64);
    BEGIN
      task_name := 'Task01';
     
      sts_task:=DBMS_SQLPA.CREATE_ANALYSIS_TASK(sqlset_name => 'STS01', task_name => task_name, description => 'Task for sql_id 94rn6s4ba24wn');
    END;
    /
     
    PL/SQL PROCEDURE successfully completed.

    When executing the task you have to decide, with execution_type parameter, which kind of execution you want to perform. A standard SPA task is made of following steps:

    • Execute the task in TEST EXECUTE mode and generate a before change task report.
    • Change what you want on your database (upgrade, optimizer parameters, statistics, …), execute the task in TEST EXECUTE mode and generate an after change task report.
    • Execute the task in COMPARE PERFORMANCE mode and generate a compare performance task report.

    Just to show one limitation of SPA I’ll first use the CONVERT SQLSET mode and generate the report:

    SQL> EXEC DBMS_SQLPA.RESET_ANALYSIS_TASK('Task01');
     
    PL/SQL PROCEDURE successfully completed.
     
    SQL> EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(task_name => 'Task01', execution_type => 'CONVERT SQLSET', execution_name => 'convert_sqlset');
     
    PL/SQL PROCEDURE successfully completed.

    You can check the task has well completed with:

    SQL> SELECT execution_name, execution_type, TO_CHAR(execution_start,'dd-mon-yyyy hh24:mi:ss') AS execution_start,
         TO_CHAR(execution_end,'dd-mon-yyyy hh24:mi:ss') AS execution_end, status
         FROM dba_advisor_executions
         WHERE task_name='Task01';
     
    EXECUTION_NAME       EXECUTION_TYPE                 EXECUTION_START               EXECUTION_END                 STATUS
    -------------------- ------------------------------ ----------------------------- ----------------------------- -----------
    convert_sqlset       CONVERT SQLSET                 29-nov-2011 15:01:26          29-nov-2011 15:01:27          COMPLETED

    Generate the report with a SQL statement like this:

    SQL> SET LONG 999999 longchunksize 100000 linesize 200 head off feedback off echo off
    SQL> spool task01_before_change.html
    SQL> SELECT DBMS_SQLPA.REPORT_ANALYSIS_TASK('Task01', 'HTML', 'ALL', 'ALL') FROM dual;
    SQL> spool off

    We can see in task01_convert_sqlset.html result file that with this particular execution all different plans are displayed, while in compare performance objective SPA is taking only one plan (the one it is currently parsing with information currently available). In any case comparing all plans of same sql_id would provide very complex reports that would probably be not usable…

    The EXPLAIN PLAN execute mode does not provide any added value as it generates the explain plan for every SQL statement of the STS, explain plans that are also displayed in TEST EXECUTE reports.

    For my test case, to simulate a database upgrade from 9iR2 to 11gR2, I first set optimizer feature to 9iR2 optimizer, execute the task in TEST EXECUTE mode and generate report, put then back optimizer parameter to default value, execute again the task in TEST EXECUTE mode and generate report and finally execute the task in COMPARE PERFORMANCE mode and generate final comparison report (the most interesting one).

    We set environment variable for report generation, check optimizer value before changing and reset the task before starting:

    SQL> SET LONG 999999 longchunksize 100000 linesize 200 head off feedback off echo off
    SQL> show parameter optimizer_features_enable
     
    NAME                                 TYPE        VALUE
    ------------------------------------ ----------- ------------------------------
    optimizer_features_enable            string      11.2.0.2
     
    SQL> EXEC DBMS_SQLPA.RESET_ANALYSIS_TASK('Task01');
     
    PL/SQL PROCEDURE successfully completed.

    We set optimizer to 9.2.0 to simulate a database upgrade situation and execute the task:

    SQL> ALTER SESSION SET optimizer_features_enable='9.2.0';
     
    SESSION altered.
     
    SQL> EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(task_name => 'Task01', execution_type => 'TEST EXECUTE', execution_name => 'before_change');
     
    PL/SQL PROCEDURE successfully completed.
     
    SQL> spool task01_before_change.html
    SQL> SELECT DBMS_SQLPA.REPORT_ANALYSIS_TASK('Task01', 'HTML', 'ALL', 'ALL') FROM dual;
    SQL> spool off

    We set back optimizer to default value and execute task again (we see that plan chosen is one of five initial plans associated with query):

    SQL> ALTER SESSION SET optimizer_features_enable='11.2.0.2';
     
    SESSION altered.
     
    SQL> EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(task_name => 'Task01', execution_type => 'TEST EXECUTE', execution_name => 'after_change');
     
    PL/SQL PROCEDURE successfully completed.
     
    SQL> spool task01_after_change.html
    SQL> SELECT DBMS_SQLPA.REPORT_ANALYSIS_TASK('Task01', 'HTML', 'ALL', 'ALL') FROM dual;
    SQL> spool off

    We can now execute a third time the task and generate the compare performance report based on the two previous test execute runs:

    SQL> EXEC DBMS_SQLPA.EXECUTE_ANALYSIS_TASK(task_name => 'Task01', execution_type => 'COMPARE PERFORMANCE', execution_name => 'compare_performance');
     
    PL/SQL PROCEDURE successfully completed.
     
    SQL> spool task01_compare_performance.html
    SQL> SELECT DBMS_SQLPA.REPORT_ANALYSIS_TASK('Task01', 'HTML', 'ALL', 'ALL') FROM dual;
    SQL> spool off

    SQL Performance Analyzer result

    First let’s check all has been well executed:

    SQL> SELECT execution_name, execution_type, TO_CHAR(execution_start,'dd-mon-yyyy hh24:mi:ss') AS execution_start,
         TO_CHAR(execution_end,'dd-mon-yyyy hh24:mi:ss') AS execution_end, advisor_name, status
         FROM dba_advisor_executions
         WHERE task_name='Task01';
     
    EXECUTION_NAME                 EXECUTION_TYPE                 EXECUTION_START               EXECUTION_END                 STATUS
    ------------------------------ ------------------------------ ----------------------------- ----------------------------- -----------
    after_change                   TEST EXECUTE                   18-nov-2011 16:18:01          18-nov-2011 16:18:18          COMPLETED
    before_change                  TEST EXECUTE                   18-nov-2011 16:16:39          18-nov-2011 16:17:11          COMPLETED
    compare_performance            COMPARE PERFORMANCE            18-nov-2011 16:18:54          18-nov-2011 16:18:57          COMPLETED
     
    SQL> SELECT last_execution,execution_type,TO_CHAR(execution_start,'dd-mon-yyyy hh24:mi:ss') AS execution_start,
         TO_CHAR(execution_end,'dd-mon-yyyy hh24:mi:ss') AS execution_end,status
         FROM dba_advisor_tasks
         WHERE task_name='Task01';
     
    LAST_EXECUTION                 EXECUTION_TYPE                 EXECUTION_START               EXECUTION_END                 STATUS
    ------------------------------ ------------------------------ ----------------------------- ----------------------------- -----------
    compare_performance            COMPARE PERFORMANCE            18-nov-2011 16:18:54          18-nov-2011 16:18:57          COMPLETED

    We can have a test overview of plan comparison with:

    SQL> col EXECUTION_NAME FOR a15
    SQL> SELECT execution_name, plan_hash_value, parse_time, elapsed_time, cpu_time,user_io_time,buffer_gets,disk_reads,direct_writes,
         physical_read_bytes,physical_write_bytes,rows_processed
         FROM dba_advisor_sqlstats
         WHERE task_name='Task01';
     
    EXECUTION_NAME  PLAN_HASH_VALUE PARSE_TIME ELAPSED_TIME   CPU_TIME USER_IO_TIME BUFFER_GETS DISK_READS DIRECT_WRITES PHYSICAL_READ_BYTES PHYSICAL_WRITE_BYTES ROWS_PROCESSED
    --------------- --------------- ---------- ------------ ---------- ------------ ----------- ---------- ------------- ------------------- -------------------- --------------
    before_change        1328242299      40664      8630688    1831720       808827      135782     117208             0           960167936                    0             60
    after_change         2949292326     167884      1808470     988850       340845       57450      38114             0           312229888                    0             60

    We can generate the text version of the two explain plans, but again html version is much more readable for a normal human being:

    SQL> col PLAN FOR a140
    SQL> SET pages 500
    SQL> SELECT p.plan_id, RPAD('(' || p.ID || ' ' || NVL(p.parent_id,'0') || ')',8) || '|' ||
         RPAD(LPAD (' ', 2*p.DEPTH) || p.operation || ' ' || p.options,40,'.') ||
         NVL2(p.object_owner||p.object_name, '(' || p.object_owner|| '.' || p.object_name || ') ', '') ||
         'Cost:' || p.COST || ' ' || NVL2(p.bytes||p.CARDINALITY,'(' || p.bytes || ' bytes, ' || p.CARDINALITY || ' rows)','') || ' ' ||
         NVL2(p.partition_id || p.partition_start || p.partition_stop,'PId:' || p.partition_id || ' PStart:' ||
         p.partition_start || ' PStop:' || p.partition_stop,'') ||
         'io cost=' || p.io_cost || ',cpu_cost=' || p.cpu_cost AS PLAN
         FROM dba_advisor_sqlplans p
         WHERE task_name='Task01'
         oder BY p.plan_id, p.id, p.parent_id;
     
       PLAN_ID PLAN
    ---------- --------------------------------------------------------------------------------------------------------------------------------------------
         89713 (0 0)   |SELECT STATEMENT .......................COST:11331 (207480 bytes, 1064 ROWS) io COST=11331,cpu_cost=
         89713 (1 0)   |  SORT GROUP BY.........................COST:11331 (207480 bytes, 1064 ROWS) io COST=11331,cpu_cost=
         89713 (2 1)   |    FILTER .............................COST:  io COST=,cpu_cost=
         89713 (3 2)   |      HASH JOIN ........................COST:11294 (207480 bytes, 1064 ROWS) io COST=11294,cpu_cost=
         89713 (4 3)   |        TABLE ACCESS BY INDEX ROWID.....(GSNX.OM_SHIPMENT_LINE) COST:3 (130 bytes, 5 ROWS) io COST=3,cpu_cost=
         89713 (5 4)   |          NESTED LOOPS .................COST:905 (166423 bytes, 1021 ROWS) io COST=905,cpu_cost=
         89713 (6 5)   |            HASH JOIN ..................COST:275 (28770 bytes, 210 ROWS) io COST=275,cpu_cost=
         89713 (7 6)   |              TABLE ACCESS FULL.........(GSNX.CORE_PARTY) COST:3 (4932 bytes, 274 ROWS) io COST=3,cpu_cost=
         89713 (8 6)   |              HASH JOIN ................COST:271 (24990 bytes, 210 ROWS) io COST=271,cpu_cost=
         89713 (9 8)   |                TABLE ACCESS FULL.......(GSNX.CORE_PARTY) COST:3 (4932 bytes, 274 ROWS) io COST=3,cpu_cost=
         89713 (10 8)  |                TABLE ACCESS FULL.......(GSNX.OM_SHIPMENT) COST:267 (21210 bytes, 210 ROWS) io COST=267,cpu_cost=
         89713 (11 5)  |            INDEX RANGE SCAN............(GSNX.OM_SHIPMENT_LINE_N1) COST:2 ( bytes, 6 ROWS) io COST=2,cpu_cost=
         89713 (12 3)  |        VIEW ...........................(SYS.VW_NSO_1) COST:10385 (637184 bytes, 19912 ROWS) io COST=10385,cpu_cost=
         89713 (13 12) |          SORT UNIQUE...................COST:10385 (423284 bytes, 19912 ROWS) io COST=8900,cpu_cost=
         89713 (14 13) |            UNION-ALL ..................COST:  io COST=,cpu_cost=
         89713 (15 14) |              SORT UNIQUE...............COST:8900 (190 bytes, 2 ROWS) io COST=8900,cpu_cost=
         89713 (16 15) |                FILTER .................COST:  io COST=,cpu_cost=
         89713 (17 16) |                  SORT GROUP BY.........COST:8900 (190 bytes, 2 ROWS) io COST=8900,cpu_cost=
         89713 (18 17) |                    NESTED LOOPS .......COST:8892 (2755 bytes, 29 ROWS) io COST=8892,cpu_cost=
         89713 (19 18) |                      HASH JOIN ........COST:8842 (1975 bytes, 25 ROWS) io COST=8842,cpu_cost=
         89713 (20 19) |                        TABLE ACCESS FUL(GSNX.MFG_WIP) COST:8808 (166191 bytes, 5361 ROWS) io COST=8808,cpu_cost=
         89713 (21 19) |                        INDEX FAST FULL (GSNX.OM_SHIPMENT_N2) COST:27 (1008432 bytes, 21009 ROWS) io COST=27,cpu_cost=
         89713 (22 18) |                      INDEX RANGE SCAN..(GSNX.MFG_WIP_LOT_QTY_N1) COST:2 (16 bytes, 1 ROWS) io COST=2,cpu_cost=
         89713 (23 16) |                  SORT AGGREGATE........COST: (9 bytes, 1 ROWS) io COST=,cpu_cost=
         89713 (24 23) |                    INDEX RANGE SCAN....(GSNX.OM_SHIPMENT_LINE_N1) COST:3 (360 bytes, 40 ROWS) io COST=3,cpu_cost=
         89713 (25 14) |              MINUS ....................COST:  io COST=,cpu_cost=
         89713 (26 25) |                SORT UNIQUE.............COST: (219010 bytes, 19910 ROWS) io COST=,cpu_cost=
         89713 (27 26) |                  INDEX FAST FULL SCAN..(GSNX.OM_SHIPMENT_UK1) COST:19 (231099 bytes, 21009 ROWS) io COST=19,cpu_cost=
         89713 (28 25) |                SORT UNIQUE.............COST: (204084 bytes, 22676 ROWS) io COST=,cpu_cost=
         89713 (29 28) |                  INDEX FAST FULL SCAN..(GSNX.MFG_WIP_N5) COST:1296 (518760 bytes, 57640 ROWS) io COST=1296,cpu_cost=
         89713 (30 2)  |      FILTER ...........................COST:  io COST=,cpu_cost=
         89713 (31 30) |        TABLE ACCESS BY INDEX ROWID.....(GSNX.MFG_WIP) COST:4 (19 bytes, 1 ROWS) io COST=4,cpu_cost=
         89713 (32 31) |          INDEX RANGE SCAN..............(GSNX.MFG_WIP_N5) COST:3 ( bytes, 1 ROWS) io COST=3,cpu_cost=
         89714 (0 0)   |SELECT STATEMENT .......................COST:19324 (252720 bytes, 1296 ROWS) io COST=19260,cpu_cost=663547063
         89714 (1 0)   |  SORT GROUP BY.........................COST:19324 (252720 bytes, 1296 ROWS) io COST=19260,cpu_cost=663547063
         89714 (2 1)   |    FILTER .............................COST:  io COST=,cpu_cost=
         89714 (3 2)   |      HASH JOIN ........................COST:16730 (252720 bytes, 1296 ROWS) io COST=16668,cpu_cost=633246741
         89714 (4 3)   |        NESTED LOOPS ...................COST:  io COST=,cpu_cost=
         89714 (5 4)   |          NESTED LOOPS .................COST:1248 (166423 bytes, 1021 ROWS) io COST=1240,cpu_cost=81128743
         89714 (6 5)   |            HASH JOIN ..................COST:617 (28770 bytes, 210 ROWS) io COST=610,cpu_cost=74949007
         89714 (7 6)   |              VIEW .....................(GSNX.INDEX$_join$_004) COST:3 (4932 bytes, 274 ROWS) io COST=2,cpu_cost=5340263
         89714 (8 7)   |                HASH JOIN ..............COST:  io COST=,cpu_cost=
         89714 (9 8)   |                  INDEX FAST FULL SCAN..(GSNX.CORE_PARTY_PK) COST:1 (4932 bytes, 274 ROWS) io COST=1,cpu_cost=77402
         89714 (10 8)  |                  INDEX FAST FULL SCAN..(GSNX.CORE_PARTY_UK2) COST:1 (4932 bytes, 274 ROWS) io COST=1,cpu_cost=77402
         89714 (11 6)  |              HASH JOIN ................COST:614 (24990 bytes, 210 ROWS) io COST=608,cpu_cost=64398724
         89714 (12 11) |                VIEW ...................(GSNX.INDEX$_join$_003) COST:3 (4932 bytes, 274 ROWS) io COST=2,cpu_cost=5340263
         89714 (13 12) |                  HASH JOIN ............COST:  io COST=,cpu_cost=
         89714 (14 13) |                    INDEX FAST FULL SCAN(GSNX.CORE_PARTY_PK) COST:1 (4932 bytes, 274 ROWS) io COST=1,cpu_cost=77402
         89714 (15 13) |                    INDEX FAST FULL SCAN(GSNX.CORE_PARTY_UK2) COST:1 (4932 bytes, 274 ROWS) io COST=1,cpu_cost=77402
         89714 (16 11) |                TABLE ACCESS FULL.......(GSNX.OM_SHIPMENT) COST:611 (21210 bytes, 210 ROWS) io COST=606,cpu_cost=53848440
         89714 (17 5)  |            INDEX RANGE SCAN............(GSNX.OM_SHIPMENT_LINE_N1) COST:2 ( bytes, 6 ROWS) io COST=2,cpu_cost=16293
         89714 (18 4)  |          TABLE ACCESS BY INDEX ROWID...(GSNX.OM_SHIPMENT_LINE) COST:3 (130 bytes, 5 ROWS) io COST=3,cpu_cost=29445
         89714 (19 3)  |        VIEW ...........................(SYS.VW_NSO_1) COST:15481 (808672 bytes, 25271 ROWS) io COST=15428,cpu_cost=544289828
         89714 (20 19) |          HASH UNIQUE...................COST:15481 (685783 bytes, 25271 ROWS) io COST=12215,cpu_cost=193587837
         89714 (21 20) |            UNION-ALL ..................COST:  io COST=,cpu_cost=
         89714 (22 21) |              HASH UNIQUE...............COST:12234 (262689 bytes, 5361 ROWS) io COST=12215,cpu_cost=193587837
         89714 (23 22) |                FILTER .................COST:  io COST=,cpu_cost=
         89714 (24 23) |                  HASH JOIN ............COST:12230 (262689 bytes, 5361 ROWS) io COST=12212,cpu_cost=180277196
         89714 (25 24) |                    TABLE ACCESS BY INDE(GSNX.MFG_WIP) COST:12169 (128664 bytes, 5361 ROWS) io COST=12152,cpu_cost=167815964
         89714 (26 25) |                      INDEX SKIP SCAN...(GSNX.MFG_WIP_N2) COST:647 ( bytes, 57640 ROWS) io COST=645,cpu_cost=16123961
         89714 (27 24) |                    INDEX FAST FULL SCAN(GSNX.OM_SHIPMENT_N2) COST:60 (525225 bytes, 21009 ROWS) io COST=60,cpu_cost=4408262
         89714 (28 23) |                  SORT AGGREGATE........COST: (9 bytes, 1 ROWS) io COST=,cpu_cost=
         89714 (29 28) |                    INDEX RANGE SCAN....(GSNX.OM_SHIPMENT_LINE_N1) COST:3 (54 bytes, 6 ROWS) io COST=3,cpu_cost=22564
         89714 (30 23) |                  SORT AGGREGATE........COST: (10 bytes, 1 ROWS) io COST=,cpu_cost=
         89714 (31 30) |                    INDEX RANGE SCAN....(GSNX.MFG_WIP_LOT_QTY_N1) COST:3 (10 bytes, 1 ROWS) io COST=3,cpu_cost=21764
         89714 (32 21) |              MINUS ....................COST:  io COST=,cpu_cost=
         89714 (33 32) |                SORT UNIQUE.............COST: (219010 bytes, 19910 ROWS) io COST=,cpu_cost=
         89714 (34 33) |                  INDEX FAST FULL SCAN..(GSNX.OM_SHIPMENT_UK1) COST:42 (231099 bytes, 21009 ROWS) io COST=42,cpu_cost=3824304
         89714 (35 32) |                SORT UNIQUE.............COST: (204084 bytes, 22676 ROWS) io COST=,cpu_cost=
         89714 (36 35) |                  INDEX FAST FULL SCAN..(GSNX.MFG_WIP_N5) COST:2972 (518760 bytes, 57640 ROWS) io COST=2946,cpu_cost=267746021
         89714 (37 2)  |      FILTER ...........................COST:  io COST=,cpu_cost=
         89714 (38 37) |        TABLE ACCESS BY INDEX ROWID.....(GSNX.MFG_WIP) COST:4 (19 bytes, 1 ROWS) io COST=4,cpu_cost=29946
         89714 (39 38) |          INDEX RANGE SCAN..............(GSNX.MFG_WIP_N5) COST:3 ( bytes, 1 ROWS) io COST=3,cpu_cost=21614
     
    73 ROWS selected.

    Below view provide potential improvement (or regression, colors are self explaining), 79% in our case. So in clear moving this database from 9iR2 to 11gR2 would provide huge gain to this particular query with no effort. Obviously this simple query is not representative of anything and you would need to add much more statements to your STS to be in better position before upgrade. Of course RAT and workload capture could be a great help for such task:

    SQL> col message FOR a80
    SQL> col FINDING_NAME FOR a30
    SQL> col EXECUTION_NAME FOR a20
    SQL> SELECT execution_name,finding_name,TYPE,impact,message FROM dba_advisor_findings WHERE task_name='Task01';
     
    EXECUTION_NAME       FINDING_NAME                   TYPE            IMPACT MESSAGE
    -------------------- ------------------------------ ----------- ---------- --------------------------------------------------------------------------------
    compare_performance  normal, SUCCESSFUL completion  INFORMATION          0 The structure OF the SQL PLAN IN execution 'before_change' IS different than its
                                                                                corresponding PLAN which IS stored IN the SQL Tuning SET.
     
    compare_performance  normal, SUCCESSFUL completion  SYMPTOM              0 The structure OF the SQL execution PLAN has changed.
    compare_performance  normal, SUCCESSFUL completion  INFORMATION 79.0460506 The performance OF this SQL has improved.

    Finally all reports generated:

    References

    • Using SQL Performance Analyzer to Test SQL Performance Impact of 9i to 10gR2 Upgrade [ID 562899.1]
    • SQL PERFORMANCE ANALYZER EXAMPLE [ID 455889.1]

    ##############ref 4

    http://czmmiao.iteye.com/blog/1914603

    The execution_type parameter of the EXECUTE_ANALYSIS_TASK procedure can take one of the following three values:
    TEST_EXECUTE:Executes all SQL statements in the captured SQL workload. The database only executes the query portion of the DML statements, in order to avoid adversely impacting user data or the database itself. The database generates both execution plans and execution statistics (for example, disk reads and buffer gets).
    COMPARE_PERFORMANCE:Compares performance between two executions of the workload performance analysis.
    EXPLAIN PLAN:Lets you generate SQL plans only, without actually executing them.

    The EXECUTE_ANALYSIS_TASK procedure executes all DML statements but ignores any DDL statements to avoid unduly affecting the test data. 
    Now we have the "before" performance information, we need to make a change so we can test the "after" performance. For this example we will simply add an index to the test table on the OBJECT_ID column. In a new SQL*Plus session create the index using the following statements.
    CONN spa_test_user/spa_test_user
    CREATE INDEX my_objects_index_01 ON my_objects(object_id);
    EXEC DBMS_STATS.gather_table_stats(USER, 'MY_OBJECTS', cascade => TRUE);
    Now, we can return to our original session and test the performance after the database change. Once again use the EXECUTE_ANALYSIS_TASK procedure, naming the analysis task "after_change".
    BEGIN
      DBMS_SQLPA.execute_analysis_task(
        task_name       => :v_task,
        execution_type  => 'test execute',
        execution_name  => 'after_change');
    END;
    /
    Once the before and after analysis tasks are complete, we must run a comparison analysis task. The following code explicitly names the analysis tasks to compare using name-value pairs in the EXECUTION_PARAMS parameter. If this is ommited, the latest two analysis runs are compared.
    BEGIN
      DBMS_SQLPA.execute_analysis_task(
        task_name        => :v_task,
        execution_type   => 'compare performance',
        execution_params => dbms_advisor.arglist(
                              'execution_name1',
                              'before_change',
                              'execution_name2',
                              'after_change')
        );
    END;
    /
    With this final analysis run complete, we can check out the comparison report using the REPORT_ANALYSIS_TASK function. The function returns a CLOB containing the report in 'TEXT', 'XML' or 'HTML' format. Its usage is shown below.
    Note. Oracle 11gR2 also includes an 'ACTIVE' format that looks more like the Enterprise Manager output.
    SET PAGESIZE 0
    SET LINESIZE 1000
    SET LONG 1000000
    SET LONGCHUNKSIZE 1000000
    SET TRIMSPOOL ON
    SET TRIM ON
    SPOOL /tmp/execute_comparison_report.htm
    SELECT DBMS_SQLPA.report_analysis_task(:v_task, 'HTML', 'ALL')
    FROM   dual;
    SPOOL OFF
    An example of this file for each available type is shown below.
    TEXT
    HTML
    XML
    ACTIVE 

    #####

    I'm more the command line type of person. Once I've understand what's going on behind the curtains I certainly switch to the GUI-click-click tools. But in the case of Real Application Testing - even though the support via the OEM GUI is excellent - sometimes I prefer to run my procedures from the command lineand check my reports in the browser.

    Recently Thomas, a colleague from Oracle ACS Support, and I were asking ourselves about the different comparison metrics for the SQL Performance Analyzer reporting We did scan the documentation but we found only examples but no complete list. Then we did ask a colleague but thanks to OEM we got an incomplete list as well.

    Finally Thomas dug it out - it's stored in the dictionary in the table V$SQLPA_METRIC

    SQL> SELECT metric_name FROM v$sqlpa_metric;

    METRIC_NAME   
    -------------------------
    PARSE_TIME               
    ELAPSED_TIME             
    CPU_TIME                 
    USER_IO_TIME             
    BUFFER_GETS              
    DISK_READS               
    DIRECT_WRITES            
    OPTIMIZER_COST           
    IO_INTERCONNECT_BYTES    

    9 rows selected.

     

    What do you do with these metrics now?

    You can use them in such a way:

    set timing on

    begin
    dbms_sqlpa.execute_analysis_task(
       task_name=>'SPA_TASK_MR07PLP_11107_12102',
       execution_name=>'Compare workload Elapsed',
       execution_type=>'compare performance',
       execution_params=>dbms_advisor.arglist(
                         'comparison_metric','elapsed_time',
                         'execution_name1','EXEC_SPA_TASK_MR07PLP_11107',
                         'execution_name2','TEST 11107 workload'),
       execution_desc=>'Compare 11107 Workload on 12102 Elapsed');
    end;
    /

    You can vary the elapsed_time in my example with the various comparison metrics mentioned in v$sqlpa_metric. 

     

    --Mike 

     

     

     

     

    ###############5

    How to Load Queries into a SQL Tuning Set (STS) 

    SOLUTION

    NOTE: The example provided below works successfully on 11g and may not work in 10g. In this case, please just list the values without any parameter names similar to the following:

    select value(p) from table(dbms_sqltune.select_cursor_cache('sql_id =''fgtq4z4vb0xx5''',NULL,NULL,NULL,NULL,1,NULL,'ALL')) p;
     

    Create a SQL Tuning Set:

    EXEC dbms_sqltune.create_sqlset('mysts');

    Load SQL into the STS


    1. From Cursor Cache

    1) To load a query with a specific sql_id

    DECLARE 
    cur sys_refcursor; 
    BEGIN 
    open cur for 
    select value(p) from table(dbms_sqltune.select_cursor_cache('sql_id = ''fgtq4z4vb0xx5''')) p; 
    dbms_sqltune.load_sqlset('mysts', cur); 
    close cur;
    END; 
    /

    2) To load queries with a specific query string and more than 1,000 buffer_gets

    DECLARE 
    cur sys_refcursor;
    BEGIN 
    open cur for 
    select value(p) from table(dbms_sqltune.select_cursor_cache('sql_text like ''%querystring%'' and buffer_gets > 1000')) p; 
    dbms_sqltune.load_sqlset('mysts', cur); 
    close cur;
    END; 
    /


    2. From AWR Snapshots


    1) Find the two snapshots you want

    select snap_id, begin_interval_time, end_interval_time from dba_hist_snapshot order by 1;

    2) To load all the queries between two snapshots

    DECLARE 
    cur sys_refcursor; 
    BEGIN 
    open cur for 
    select value(p) from table(dbms_sqltune.select_workload_repository(begin_snap => 2245, end_snap => 2248)) p; 
    dbms_sqltune.load_sqlset('mysts', cur); 
    close cur;
    END; 
    /

    3) To load a query with a specific sql_id and plan_hash_value

    DECLARE 
    cur sys_refcursor; 
    BEGIN 
    open cur for 
    select value(p) from table(dbms_sqltune.select_workload_repository(begin_snap => 2245, end_snap => 2248, basic_filter => 'sql_id = ''fgtq4z4vb0xx5'' and plan_hash_value = 431456802')) p; 
    dbms_sqltune.load_sqlset('mysts', cur); 
    close cur;
    END; 
    /
    NOTE: "basic_filter" is the SQL predicate to filter the SQL from the cursor cache defined on attributes of the SQLSET_ROW.  If basic_filter is not set by the caller, the subprogram captures only statements of the type CREATE TABLE, INSERT, SELECT, UPDATE, DELETE, and MERGE. 

    CREATE TYPE sqlset_row AS object (
    sql_id VARCHAR(13),
    force_matching_signature NUMBER,
    sql_text CLOB,
    object_list sql_objects,
    bind_data RAW(2000),
    parsing_schema_name VARCHAR2(30),
    module VARCHAR2(48),
    action VARCHAR2(32),
    elapsed_time NUMBER,
    cpu_time NUMBER,
    buffer_gets NUMBER,
    disk_reads NUMBER,
    direct_writes NUMBER,
    rows_processed NUMBER,
    fetches NUMBER,
    executions NUMBER,
    end_of_fetch_count NUMBER,
    optimizer_cost NUMBER,
    optimizer_env RAW(2000),
    priority NUMBER,
    command_type NUMBER,
    first_load_time VARCHAR2(19),
    stat_period NUMBER,
    active_stat_period NUMBER,
    other CLOB,
    plan_hash_value NUMBER,
    sql_plan sql_plan_table_type,
    bind_list sql_binds) ;
     


    3. From an AWR Baseline

    1) Find the baseline you want to load

    select baseline_name, start_snap_id, end_snap_id from dba_hist_baseline;

    2) Load queries from the baseline

    DECLARE 
    cur sys_refcursor; 
    BEGIN 
    open cur for 
    select value(p) from table(dbms_sqltune.select_workload_repository('MY_BASELINE')) p; 
    dbms_sqltune.load_sqlset('mysts', cur); 
    close cur;
    END; 
    /

    4. From another SQL Tuning Set

    1) Find the SQL Tuning Set you want to load

    select name, owner, statement_count from dba_sqlset;

    2) Load queries from the SQL Tuning Set

    DECLARE 
    cur sys_refcursor; 
    BEGIN 
    open cur for 
    select value(p) from table(dbms_sqltune.select_sqlset(sqlset_name => 'HR_STS', sqlset_owner => 'HR', basic_filter => 'sql_text like ''%querystring%''')) p; 
    dbms_sqltune.load_sqlset('mysts', cur); 
    close cur;
    END; 
    /


    5. From 10046 trace files (11g+)

    1) Loading into a SQL Tuning Set in the same database that it originated from

    i. Create a directory object for the directory where the trace files are.

    create directory my_dir as '/home/oracle/trace';

    ii. Load the queries


    DECLARE 
    cur sys_refcursor; 
    BEGIN 
    open cur for 
    select value(p) from table(dbms_sqltune.select_sql_trace(directory=>'MY_DIR', file_name=>'%.trc')) p;
    dbms_sqltune.load_sqlset('mysts', cur); 
    close cur;
    END; 
    /

    2) Loading into a SQL Tuning Set in a different database

    i. Create a mapping table from the database where the trace files were captured.

    create table mapping as
    select object_id id, owner, substr(object_name, 1, 30) name
    from dba_objects
    union all
    select user_id id, username owner, null name
    from dba_users;

     
    ii. Copy the trace files into a directory of the target server and create a directory object for the directory. And import the mapping table into the target database.

    create directory my_dir as '/home/oracle/trace';


    iii. Specify the mapping table when loading the queries.


    DECLARE 
    cur sys_refcursor; 
    BEGIN 
    open cur for 
    select value(p) from table(dbms_sqltune.select_sql_trace(directory=>'MY_DIR', file_name=>'%.trc', mapping_table_name=> 'MAPPING', mapping_table_owner=> 'HR')) p;
    dbms_sqltune.load_sqlset('mysts', cur); 
    close cur;
    END; 
    /

     

     -----spa

    :ORA-13757: "SQL Tuning Set" "OCMHU_STS" owned by user "SYS" is active.

     


    -方法:

     http://blog.itpub.net/14359/viewspace-1253599/

    STEP 1:
    select owner,description, created,last_modified,TASK_NAME
    from DBA_ADVISOR_TASKS where owner='DBMGR'

    STEP 2:

    (7) You can drop sql tuning set by issuing following command :
    SQL>BEGIN
    DBMS_SQLTUNE.DROP_SQLSET(
    sqlset_name => 'STS_SQLSET'
    );
    END;
    /
    PL/SQL procedure successfully completed.


    step 3:

    (5) Check the no. of dependent task using below mentioned query.
    SQL> SELECT count(*)
    FROM wri$_sqlset_definitions d, wri$_sqlset_references r
    WHERE d.name = 'STS_SQLSET'
    AND r.sqlset_id = d.id;
    COUNT(*)
    ———-
    0
    In normal case the output of the query should be “0”. In this case, it is taking advisory task “SPA01″ as it has not been deleted from database.
    (6) You need to manually edit table and remove the entry which contains information regarding sql tuning task :
    conn / as sysdba
    delete from wri$_sqlset_references
    where sqlset_id in (select id
    from wri$_sqlset_definitions
    where name in ('SPA01'));
    commit;
    This command will update oracle table and will remove dependency from sql tuning set .


    STEP 4:

    (3) To check all the dependent advisory tasks attached to sql tuning set you need to issue following command :
    SQL> SET WRAP OFF
    SQL> SET LINE 140
    SQL> COL NAME FOR A15
    SQL> COL DESCRIPTION FOR A50 WRAPPED
    SQL>
    SQL> select description, created, owner
    from DBA_SQLSET_REFERENCES
    where sqlset_name ='STS_SQLSET';
    DESCRIPTION CREATED OWNER
    -------------------------------------------------- ------------------- ----------
    created by: SQL Performance Analyzer - task: SPA01 2014-08-05 16:22:27 SYS
    From the above output we can evaluate that task “SPA01″ is dependent on sql tuning set “OCMHU_STS”. So, if you want to drop sql tuning set ”OCMHU_STS” you need to drop task ”SPA01“.
    NOTE : Think before dropping sql tuning task as if you drop it, all the information related to sql_profile, stats, indexes related to this advisory task will be deleted.
    (4) To check the details regarding SQL Performance Analyzer - task: “SPA01” you can issue following command :
    a. Normal Output :
    SQL> SET WRAP OFF
    SQL> SET LINE 140
    SQL> COL NAME FOR A15
    SQL> COL OWNER FOR A10
    SQL> COL DESCRIPTION FOR A50 WRAPPED
    SQL>
    SQL> select owner,description, created,last_modified
    from DBA_ADVISOR_TASKS
    where task_name = 'TASK_10G';
    OWNER DESCRIPTION CREATED LAST_MODIFIED
    ---------- -------------------------------------------------- ------------------- -------------------
    SYS 2014-08-05 16:22:26 2014-08-05 17:25:12
    If you are getting the above mentioned output then you can solve the issue by dropping the abve mentioned sql advisory tasks. The command for dropping sql advisory task is mentioned below.

    SQL> execute dbms_sqltune.drop_tuning_task('TASK_10G');
    PL/SQL procedure successfully completed.
    b. Issue based output :


  • 相关阅读:
    JS中encodeURIComponent在PHP中实现的办法_tdweb的博客,仅仅是个博客_百度空间
    废弃的java 爬虫代码
    c#实现Javascript的encodeURIComponent()函数
    Encode query with Python
    Chunked decoding in python
    python implemention javascript encodeURIComponent
    Java MongoDB : Insert a document
    tar zcvf ./xxx.tar.gz ./directory
    MyStringUtils test
    application/xwwwformurlencoded
  • 原文地址:https://www.cnblogs.com/feiyun8616/p/9173892.html
Copyright © 2011-2022 走看看