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吧??

 

posted @ 2021-02-05 11:28  PiscesCanon  阅读(289)  评论(0编辑  收藏  举报