zoukankan      html  css  js  c++  java
  • Oracle qb_name导致SPM绑定的执行计划错乱

    Oracle qb_name导致SPM绑定的执行计划错乱

    前言

    最近生产在为SQL使用SPM绑定执行计划的时候,出现执行计划错乱的问题。

    以前都是可以成功绑定的,此次出现问题后查看对应SQL_HANDLE和PLAN_NAME的执行计划发现,该执行计划并非我想要的执行计划。

    以前绑过好几条都是成功的,这个唯一不同的是使用了qb_name之后导致了这个问题。

    怀疑是BUG,但是并不能再mos上搜索到匹配的问题场景。

    接下来模拟下该场景。

    模拟

    10:28:23 ZKM@test1(1068)> create table t1 as select * from dba_objects;
    
    Table created.
    
    Elapsed: 00:00:01.01
    10:28:53 ZKM@test1(1068)> create table t2 as select * from dba_objects;
    
    Table created.
    
    Elapsed: 00:00:00.67

    目标SQL为:

    select count(*) from t1 where not exists ( select 1 from t2 where t1.owner=t2.owner);

    运行一遍查找该SQL的SQL ID号:

    11:13:08 ZKM@test1(1068)> select count(*) from t1 where not exists ( select 1 from t2 where t1.owner=t2.owner);
    
      COUNT(*)
    ----------
             0
    
    Elapsed: 00:00:00.06
    11:13:13 ZKM@test1(1068)> select sql_id from v$sql where sql_text='select count(*) from t1 where not exists ( select 1 from t2 where t1.owner=t2.owner)' and rownum=1;
    
    SQL_ID
    ---------------
    c9dku2pajc2t1
    
    Elapsed: 00:00:00.00

    默认情况下,该SQL执行计划为“hash join anti”。

    11:15:35 ZKM@test1(1068)> set pagesize 9999 long 9999 line 500 timing on
    11:15:35 ZKM@test1(1068)> alter session set statistics_level=all;
    
    Session altered.
    
    Elapsed: 00:00:00.00
    11:15:35 ZKM@test1(1068)> select count(*) from t1 where not exists ( select 1 from t2 where t1.owner=t2.owner);
    
      COUNT(*)
    ----------
             0
    
    Elapsed: 00:00:00.06
    11:15:37 ZKM@test1(1068)> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
    
    PLAN_TABLE_OUTPUT
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    SQL_ID  c9dku2pajc2t1, child number 2
    -------------------------------------
    select count(*) from t1 where not exists ( select 1 from t2 where
    t1.owner=t2.owner)
    
    Plan hash value: 1513027705
    
    -----------------------------------------------------------------------------------------------------------------
    | Id  | Operation           | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
    -----------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT    |      |      1 |        |      1 |00:00:00.05 |     874 |       |       |          |
    |   1 |  SORT AGGREGATE     |      |      1 |      1 |      1 |00:00:00.05 |     874 |       |       |          |
    |*  2 |   HASH JOIN ANTI    |      |      1 |  22186 |      0 |00:00:00.05 |     874 |  2952K|  2624K| 3184K (0)|
    |   3 |    TABLE ACCESS FULL| T1   |      1 |  22186 |  31002 |00:00:00.01 |     437 |       |       |          |
    |   4 |    TABLE ACCESS FULL| T2   |      1 |  30838 |  31003 |00:00:00.01 |     437 |       |       |          |
    -----------------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - access("T1"."OWNER"="T2"."OWNER")
    
    Note
    -----
       - dynamic sampling used for this statement (level=2)
    
    
    26 rows selected.
    
    Elapsed: 00:00:00.03

    接下来使用hint,让cbo走出NESTED LOOP ANTI,如下SQL为:

    select /*+ nl_aj(@b1) */ count(*) from t1 where not exists ( select /*+ qb_name(b1) */ 1 from t2 where t1.owner=t2.owner);

    详细的执行信息:

    11:18:07 ZKM@test1(1068)> select /*+ nl_aj(@b1) */ count(*) from t1 where not exists ( select /*+ qb_name(b1) */ 1 from t2 where t1.owner=t2.owner);
    
      COUNT(*)
    ----------
             0
    
    Elapsed: 00:00:00.20
    11:18:08 ZKM@test1(1068)> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
    
    PLAN_TABLE_OUTPUT
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    SQL_ID  7a9z1syzrc9nw, child number 0
    -------------------------------------
    select /*+ nl_aj(@b1) */ count(*) from t1 where not exists ( select /*+
    qb_name(b1) */ 1 from t2 where t1.owner=t2.owner)
    
    Plan hash value: 4091582738
    
    --------------------------------------------------------------------------------------
    | Id  | Operation           | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
    --------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT    |      |      1 |        |      1 |00:00:00.20 |   29593 |
    |   1 |  SORT AGGREGATE     |      |      1 |      1 |      1 |00:00:00.20 |   29593 |
    |   2 |   NESTED LOOPS ANTI |      |      1 |  22186 |      0 |00:00:00.20 |   29593 |
    |   3 |    TABLE ACCESS FULL| T1   |      1 |  22186 |  31002 |00:00:00.02 |     437 |
    |*  4 |    TABLE ACCESS FULL| T2   |    110 |      1 |    110 |00:00:00.17 |   29156 |
    --------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       4 - filter("T1"."OWNER"="T2"."OWNER")
    
    Note
    -----
       - dynamic sampling used for this statement (level=2)
    
    
    26 rows selected.
    
    Elapsed: 00:00:00.03

    接下来使用SPM添加基线并查看该基线的执行计划,可以看出默认的执行计划为HASH JOIN ANTI的:

    11:19:12 ZKM@test1(1068)> declare
    11:19:13   2    l_plans_loaded  PLS_INTEGER;
    11:19:13   3  begin
    11:19:13   4    l_plans_loaded := DBMS_SPM.load_plans_from_cursor_cache(sql_id => 'c9dku2pajc2t1');
    11:19:13   5    DBMS_OUTPUT.put_line('Plans Loaded: ' || l_plans_loaded);
    11:19:13   6  END;
    11:19:13   7  /
    
    PL/SQL procedure successfully completed.
    
    Elapsed: 00:00:00.09
    11:19:13 ZKM@test1(1068)> col SQL_HANDLE for a25
    11:19:18 ZKM@test1(1068)> col plan_name for a35
    11:19:18 ZKM@test1(1068)> select signature,sql_handle,plan_name,origin,enabled,accepted,autopurge from dba_sql_plan_baselines where sql_text like 'select count(*) from t1 where not exists ( select 1 from t2 where t1.owner=t2.owner)';
    
     SIGNATURE SQL_HANDLE                PLAN_NAME                           ORIGIN                                     ENABLED   ACCEPTED  AUTOPURGE
    ---------- ------------------------- ----------------------------------- ------------------------------------------ --------- --------- ---------
    1.1694E+19 SQL_a24a103b54bc3969      SQL_PLAN_a4khh7dabsfb9679d9149      MANUAL-LOAD                                YES       YES       YES
    
    Elapsed: 00:00:00.00
    11:19:19 ZKM@test1(1068)> select * from table(dbms_xplan.display_sql_plan_baseline(sql_handle=>'SQL_a24a103b54bc3969',plan_name=>'SQL_PLAN_a4khh7dabsfb9679d9149'));
    
    PLAN_TABLE_OUTPUT
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    --------------------------------------------------------------------------------
    SQL handle: SQL_a24a103b54bc3969
    SQL text: select count(*) from t1 where not exists ( select 1 from t2 where
              t1.owner=t2.owner)
    --------------------------------------------------------------------------------
    
    --------------------------------------------------------------------------------
    Plan name: SQL_PLAN_a4khh7dabsfb9679d9149         Plan id: 1738379593
    Enabled: YES     Fixed: NO      Accepted: YES     Origin: MANUAL-LOAD
    --------------------------------------------------------------------------------
    
    Plan hash value: 1513027705
    
    ----------------------------------------------------------------------------
    | Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------------
    |   0 | SELECT STATEMENT    |      |     1 |    34 |   248   (1)| 00:00:01 |
    |   1 |  SORT AGGREGATE     |      |     1 |    34 |            |          |
    |*  2 |   HASH JOIN ANTI    |      | 36675 |  1217K|   248   (1)| 00:00:01 |
    |   3 |    TABLE ACCESS FULL| T1   | 36675 |   608K|   124   (1)| 00:00:01 |
    |   4 |    TABLE ACCESS FULL| T2   | 36675 |   608K|   124   (1)| 00:00:01 |
    ----------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - access("T1"."OWNER"="T2"."OWNER")
    
    28 rows selected.
    
    Elapsed: 00:00:00.15

    然后把我们想要的执行计划添加进去,并查看新添加的plan_name对应的执行计划:

    11:20:56 ZKM@test1(1068)> DECLARE
    11:20:57   2   k1 pls_integer;
    11:20:57   3  begin
    11:20:57   4  k1 := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE (
    11:20:57   5  sql_id=>'7a9z1syzrc9nw',
    11:20:57   6  plan_hash_value=>4091582738,sql_handle=>'SQL_a24a103b54bc3969'
    11:20:57   7  );
    11:20:57   8  end;
    11:20:57   9  /
    
    PL/SQL procedure successfully completed.
    
    Elapsed: 00:00:00.04
    11:20:57 ZKM@test1(1068)> select signature,sql_handle,plan_name,origin,enabled,accepted,autopurge from dba_sql_plan_baselines where sql_text like 'select count(*) from t1 where not exists ( select 1 from t2 where t1.owner=t2.owner)';
    
     SIGNATURE SQL_HANDLE                PLAN_NAME                           ORIGIN                                     ENABLED   ACCEPTED  AUTOPURGE
    ---------- ------------------------- ----------------------------------- ------------------------------------------ --------- --------- ---------
    1.1694E+19 SQL_a24a103b54bc3969      SQL_PLAN_a4khh7dabsfb9679d9149      MANUAL-LOAD                                YES       YES       YES
    1.1694E+19 SQL_a24a103b54bc3969      SQL_PLAN_a4khh7dabsfb96a2152fd      MANUAL-LOAD                                YES       YES       YES
    
    Elapsed: 00:00:00.01
    11:21:10 ZKM@test1(1068)> select * from table(dbms_xplan.display_sql_plan_baseline(sql_handle=>'SQL_a24a103b54bc3969',plan_name=>'SQL_PLAN_a4khh7dabsfb96a2152fd'));
    
    PLAN_TABLE_OUTPUT
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    --------------------------------------------------------------------------------
    SQL handle: SQL_a24a103b54bc3969
    SQL text: select count(*) from t1 where not exists ( select 1 from t2 where
              t1.owner=t2.owner)
    --------------------------------------------------------------------------------
    
    --------------------------------------------------------------------------------
    Plan name: SQL_PLAN_a4khh7dabsfb96a2152fd         Plan id: 1780568829
    Enabled: YES     Fixed: NO      Accepted: YES     Origin: MANUAL-LOAD
    --------------------------------------------------------------------------------
    
    Plan hash value: 59119136
    
    ----------------------------------------------------------------------------
    | Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------------
    |   0 | SELECT STATEMENT    |      |     1 |    17 |  3566   (1)| 00:00:03 |
    |   1 |  SORT AGGREGATE     |      |     1 |    17 |            |          |
    |*  2 |   FILTER            |      |       |       |            |          |
    |   3 |    TABLE ACCESS FULL| T1   | 36675 |   608K|   124   (1)| 00:00:01 |
    |*  4 |    TABLE ACCESS FULL| T2   |   308 |  5236 |     3   (0)| 00:00:01 |
    ----------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - filter( NOT EXISTS (SELECT 0 FROM "T2" "T2" WHERE
                  "T2"."OWNER"=:B1))
       4 - filter("T2"."OWNER"=:B1)
    
    Note
    -----
       - dynamic sampling used for this statement (level=2)
    
    34 rows selected.
    
    Elapsed: 00:00:00.07

    问题来了,可以看出该执行计划和我们添加的plan hash value:4091582738完全不同,而且该计划的id2步骤显示为filter。

    操作完全没问题,估计就是个BUG了。

    接下来,不使用qb_name这个hint,直接在子查询里边使用nl_aj,看看是否能够正常出现想要的执行计划。

    对应SQL为:

    select count(*) from t1 where not exists ( select /*+ nl_aj */ 1 from t2 where t1.owner=t2.owner);

    详细的执行信息如下:

    11:25:36 ZKM@test1(1068)> select count(*) from t1 where not exists ( select /*+ nl_aj */ 1 from t2 where t1.owner=t2.owner);
    
      COUNT(*)
    ----------
             0
    
    Elapsed: 00:00:00.20
    11:25:36 ZKM@test1(1068)> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
    
    PLAN_TABLE_OUTPUT
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    SQL_ID  1wkqm7d8319gw, child number 0
    -------------------------------------
    select count(*) from t1 where not exists ( select /*+ nl_aj */ 1 from
    t2 where t1.owner=t2.owner)
    
    Plan hash value: 4091582738
    
    --------------------------------------------------------------------------------------
    | Id  | Operation           | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
    --------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT    |      |      1 |        |      1 |00:00:00.19 |   29593 |
    |   1 |  SORT AGGREGATE     |      |      1 |      1 |      1 |00:00:00.19 |   29593 |
    |   2 |   NESTED LOOPS ANTI |      |      1 |  22186 |      0 |00:00:00.19 |   29593 |
    |   3 |    TABLE ACCESS FULL| T1   |      1 |  22186 |  31002 |00:00:00.02 |     437 |
    |*  4 |    TABLE ACCESS FULL| T2   |    110 |      1 |    110 |00:00:00.16 |   29156 |
    --------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       4 - filter("T1"."OWNER"="T2"."OWNER")
    
    Note
    -----
       - dynamic sampling used for this statement (level=2)
    
    
    26 rows selected.
    
    Elapsed: 00:00:00.05
    11:25:38 ZKM@test1(1068)> DECLARE
    11:25:59   2   k1 pls_integer;
    11:25:59   3  begin
    11:25:59   4  k1 := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE (
    11:25:59   5  sql_id=>'1wkqm7d8319gw',
    11:25:59   6  plan_hash_value=>4091582738,sql_handle=>'SQL_a24a103b54bc3969'
    11:25:59   7  );
    11:25:59   8  end;
    11:25:59   9  /
    
    PL/SQL procedure successfully completed.
    
    Elapsed: 00:00:00.06
    11:25:59 ZKM@test1(1068)> select signature,sql_handle,plan_name,origin,enabled,accepted,autopurge from dba_sql_plan_baselines where sql_text like 'select count(*) from t1 where not exists ( select 1 from t2 where t1.owner=t2.owner)';
    
     SIGNATURE SQL_HANDLE                PLAN_NAME                           ORIGIN                                     ENABLED   ACCEPTED  AUTOPURGE
    ---------- ------------------------- ----------------------------------- ------------------------------------------ --------- --------- ---------
    1.1694E+19 SQL_a24a103b54bc3969      SQL_PLAN_a4khh7dabsfb9679d9149      MANUAL-LOAD                                YES       YES       YES
    1.1694E+19 SQL_a24a103b54bc3969      SQL_PLAN_a4khh7dabsfb96a2152fd      MANUAL-LOAD                                YES       YES       YES
    
    Elapsed: 00:00:00.00
    11:26:06 ZKM@test1(1068)> select * from table(dbms_xplan.display_sql_plan_baseline(sql_handle=>'SQL_a24a103b54bc3969',plan_name=>'SQL_PLAN_a4khh7dabsfb96a2152fd'));
    
    PLAN_TABLE_OUTPUT
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    --------------------------------------------------------------------------------
    SQL handle: SQL_a24a103b54bc3969
    SQL text: select count(*) from t1 where not exists ( select 1 from t2 where
              t1.owner=t2.owner)
    --------------------------------------------------------------------------------
    
    --------------------------------------------------------------------------------
    Plan name: SQL_PLAN_a4khh7dabsfb96a2152fd         Plan id: 1780568829
    Enabled: YES     Fixed: NO      Accepted: YES     Origin: MANUAL-LOAD
    --------------------------------------------------------------------------------
    
    Plan hash value: 4091582738
    
    ----------------------------------------------------------------------------
    | Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------------
    |   0 | SELECT STATEMENT    |      |     1 |    34 |  4480K  (1)| 00:53:03 |
    |   1 |  SORT AGGREGATE     |      |     1 |    34 |            |          |
    |   2 |   NESTED LOOPS ANTI |      | 36675 |  1217K|  4480K  (1)| 00:53:03 |
    |   3 |    TABLE ACCESS FULL| T1   | 36675 |   608K|   124   (1)| 00:00:01 |
    |*  4 |    TABLE ACCESS FULL| T2   |     1 |    17 |   122   (0)| 00:00:01 |
    ----------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       4 - filter("T1"."OWNER"="T2"."OWNER")
    
    28 rows selected.
    
    Elapsed: 00:00:00.06

    可以看出,已经正常出现想要的执行计划了。。

    这估计是BUG吧??

  • 相关阅读:
    实验三-并发程序 20175201张驰
    20175201 20175215 20175229 实验二 固件程序设计
    20175201 20175215 20175229 实验一 开发环境的熟悉
    #20175201 实验五 网络编程与安全
    云班课选做
    2019-2020-12 20175313 20175328 20175329 实验五 通讯协议设计
    2019-2020-1 20175313 20175328 20175329 实验四 外设驱动程序设计
    2019-2020-1 20175313 20175328 20175329 实验三 并发程序
    20175329&20175313&20175318 2019-2020 《信息安全系统设计基础》实验三
    20175329&20175313&20175318 2019-2020 《信息安全系统设计基础》实验二
  • 原文地址:https://www.cnblogs.com/PiscesCanon/p/14376778.html
Copyright © 2011-2022 走看看