FIRST_ROWS优化模式访问远端表可能导致错误结果(二)

Oracle9204上碰到了这个问题,FIRST_ROWS优化模式下,通过数据库链访问远端表,且SQL包括IN子查询语句时,优化器可能给出错误的执行计划,从而导致结果集出现重复记录。

这一篇继续研究问题和版本的关系,以及相应的解决方法。

FIRST_ROWS优化模式访问远端表可能导致错误结果(一):http://yangtingkun.itpub.net/post/468/460444

 

 

上一篇讨论了问题和哪些因素有关,下面看看这个问题是否和版本有关。由于上面一篇文章中所有的测试都是在9.2.0.4版本上进行的,下面分别将远端库和本地库更改为10.2,检查错误是否依然存在:

SQL> CONN YANGTK/YANGTK@YTK102
已连接。
SQL> SELECT * FROM V$VERSION;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE    10.2.0.1.0      Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production

SQL> CREATE TABLE T AS SELECT * FROM DBA_OBJECTS
  2  WHERE WNER = 'SYS'
  3  AND OBJECT_TYPE IN ('TABLE', 'SEQUENCE', 'SYNONYM');

表已创建。

SQL> CREATE TABLE T1 AS SELECT * FROM DBA_TAB_PRIVS;

表已创建。

SQL> CREATE INDEX IND_T1_GRANTEE ON T1(GRANTEE);

索引已创建。

SQL> CREATE INDEX IND_T1_NAME ON T1(TABLE_NAME);

索引已创建。

SQL> CREATE UNIQUE INDEX IND_T_NAME ON T(OBJECT_NAME);

索引已创建。

SQL> CONN YANGTK/YANGTK@YTK92
已连接。
SQL> CREATE DATABASE LINK YTK102 USING 'YTK102';

数据库链接已创建。

SQL> SET AUTOT ON EXP
SQL> SELECT OBJECT_ID, OBJECT_NAME FROM T@YTK102
  2  WHERE OBJECT_NAME IN
  3  (
  4   SELECT TABLE_NAME FROM T1@YTK102
  5   WHERE GRANTEE IN
  6    (SELECT GRANTEE FROM T1@YTK102 WHERE TABLE_NAME = 'HELP')
  7  )
  8  AND OBJECT_NAME NOT IN (SELECT SYNONYM_NAME FROM T2);

 OBJECT_ID OBJECT_NAME
---------- ------------------------------
     46535 AW$AWCREATE
     46541 AW$AWCREATE10G
     46529 AW$AWMD
     46553 AW$AWREPORT
     46547 AW$AWXML
     46523 AW$EXPRESS
      7103 IMPDP_STATS
      7102 KU$NOEXP_TAB
      4312 ODCI_SECOBJ$
      4313 ODCI_WARNINGS$
     46619 OLAPI_HISTORY
     46618 OLAPI_HISTORY_SEQ
     46623 OLAPI_IFACE_OBJECT_HISTORY
     46625 OLAPI_IFACE_OP_HISTORY
     46629 OLAPI_MEMORY_HEAP_HISTORY
     46627 OLAPI_MEMORY_OP_HISTORY
     46621 OLAPI_SESSION_HISTORY
     46560 OLAPTABLEVELS
     46563 OLAPTABLEVELTUPLES
     48705 OLAP_OLEDB_FUNCTIONS_PVT
     48668 OLAP_OLEDB_KEYWORDS
     48671 OLAP_OLEDB_MDPROPS
     48669 OLAP_OLEDB_MDPROPVALS
      8706 PLAN_TABLE$
      3989 PSTUBTBL
      5287 SCHEDULER$_JOBSUFFIX_S
      4161 WRI$_ADV_ASA_RECO_DATA

已选择27行。


执行计划
----------------------------------------------------------
   0      SELECT STATEMENT ptimizer=CHOOSE
   1    0   FILTER
   2    1     MERGE JOIN
   3    2       SORT (JOIN)
   4    3         REMOTE*                                              YTK102.YTK_THINKPAD
   5    2       SORT (JOIN)
   6    5         VIEW OF 'VW_NSO_1'
   7    6           REMOTE*                                            YTK102.YTK_THINKPAD
   8    1     TABLE ACCESS (FULL) OF 'T2'


   4 SERIAL_FROM_REMOTE            SELECT "OBJECT_NAME","OBJECT_ID" FROM "T" "S
                                   YS_ALIAS_1"

   7 SERIAL_FROM_REMOTE            SELECT /*+ */ DISTINCT "A1"."TABLE_NAME" FRO
                                   M "T1" "A1" WHERE  EXISTS (SELECT 0


SQL> SELECT /*+ FIRST_ROWS */ OBJECT_ID, OBJECT_NAME FROM T@YTK102
  2  WHERE OBJECT_NAME IN
  3  (
  4   SELECT TABLE_NAME FROM T1@YTK102
  5   WHERE GRANTEE IN
  6    (SELECT GRANTEE FROM T1@YTK102 WHERE TABLE_NAME = 'HELP')
  7  )
  8  AND OBJECT_NAME NOT IN (SELECT SYNONYM_NAME FROM T2);

 OBJECT_ID OBJECT_NAME
---------- ------------------------------
      3989 PSTUBTBL
      3989 PSTUBTBL
      4161 WRI$_ADV_ASA_RECO_DATA
      4161 WRI$_ADV_ASA_RECO_DATA
      4161 WRI$_ADV_ASA_RECO_DATA
      4312 ODCI_SECOBJ$
      4312 ODCI_SECOBJ$
.
.
.
     46629 OLAPI_MEMORY_HEAP_HISTORY
     46629 OLAPI_MEMORY_HEAP_HISTORY
     46629 OLAPI_MEMORY_HEAP_HISTORY
     48668 OLAP_OLEDB_KEYWORDS
     48669 OLAP_OLEDB_MDPROPVALS
     48671 OLAP_OLEDB_MDPROPS
     48705 OLAP_OLEDB_FUNCTIONS_PVT

已选择105行。


执行计划
----------------------------------------------------------
   0      SELECT STATEMENT ptimizer=HINT: FIRST_ROWS (Cost=2930 Card=
          77 Bytes=7392)

   1    0   FILTER
   2    1     NESTED LOOPS (Cost=928 Card=77 Bytes=7392)
   3    2       VIEW OF 'VW_NSO_1' (Cost=49 Card=874 Bytes=14858)
   4    3         REMOTE*                                              YTK102.YTK_THINKPAD
   5    2       REMOTE* (Cost=1 Card=1 Bytes=79)                       YTK102.YTK_THINKPAD
   6    1     INDEX (FULL SCAN) OF 'IND_T2_NAME' (NON-UNIQUE) (Cost=26
           Card=511 Bytes=8687)

 

   4 SERIAL_FROM_REMOTE            SELECT "A1"."TABLE_NAME" FROM "T1" "A1" WHER
                                   E  EXISTS (SELECT 0 FROM "T1" "A2" W

   5 SERIAL_FROM_REMOTE            SELECT "OBJECT_NAME","OBJECT_ID" FROM "T" "S
                                   YS_ALIAS_1" WHERE "OBJECT_NAME"=:1

如果远端数据库是10g,那么问题仍然存在,其实这也可以理解,因为执行计划是本地产生的,所以远端数据库的版本并不重要。

下面将SQL10g上执行,访问远端9I数据库:

SQL> CONN YANGTK/YANGTK@YTK102
已连接。
SQL> CREATE DATABASE LINK YTK92 USING 'YTK92';

数据库链接已创建。

SQL> SET AUTOT ON EXP
SQL> CREATE TABLE T2 AS SELECT * FROM DBA_SYNONYMS;

表已创建。

SQL> CREATE INDEX IND_T2_NAME ON T2(SYNONYM_NAME);

索引已创建。

SQL> SELECT OBJECT_ID, OBJECT_NAME FROM T@YTK92
  2  WHERE OBJECT_NAME IN
  3  (
  4   SELECT TABLE_NAME FROM T1@YTK92
  5   WHERE GRANTEE IN
  6    (SELECT GRANTEE FROM T1@YTK92 WHERE TABLE_NAME = 'HELP')
  7  )
  8  AND OBJECT_NAME NOT IN (SELECT SYNONYM_NAME FROM T2);

 OBJECT_ID OBJECT_NAME
---------- ------------------------------
     29559 AW$AWCREATE
     29567 AW$AWMD
     29527 AW$EXPRESS
      3387 ODCI_SECOBJ$
      3388 ODCI_WARNINGS$
     29573 OLAPTABLEVELS
     29576 OLAPTABLEVELTUPLES
      3200 PSTUBTBL

已选择8行。


执行计划
----------------------------------------------------------
Plan hash value: 4134023224

-------------------------------------------------------------------------------------------------
| Id  | Operation         | Name        | Rows  | Bytes | Cost (%CPU)| Time     | Inst   |IN-OUT|
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |             |   113 | 10848 |    79   (3)| 00:00:01 |        |      |
|*  1 |  FILTER           |             |       |       |            |          |        |      |
|*  2 |   HASH JOIN       |             |   113 | 10848 |    23  (14)| 00:00:01 |        |      |
|   3 |    VIEW           | VW_NSO_1    |   113 |  1921 |    19  (11)| 00:00:01 |        |      |
|   4 |     REMOTE        |             |       |       |            |          |  YTK92 | R->S |
|   5 |    REMOTE         | T           |   899 | 71021 |     3   (0)| 00:00:01 |  YTK92 | R->S |
|*  6 |   INDEX RANGE SCAN| IND_T2_NAME |   210 |  3570 |     1   (0)| 00:00:01 |        |      |
-------------------------------------------------------------------------------------------------

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

   1 - filter( NOT EXISTS (SELECT /*+ */ 0 FROM "T2" "T2" WHERE "SYNONYM_NAME"=:B1))
   2 - access("OBJECT_NAME"="$nso_col_1")
   6 - access("SYNONYM_NAME"=:B1)

Remote SQL Information (identified by operation id):
----------------------------------------------------

   4 - EXPLAIN PLAN SET STATEMENT_ID='PLUS1563' INTO PLAN_TABLE@! FOR SELECT DISTINCT
       "A1"."TABLE_NAME" FROM "T1" "A2","T1" "A1" WHERE "A1"."GRANTEE"="A2"."GRANTEE" AND
       "A2"."TABLE_NAME"='HELP' (accessing 'YTK92.YTK_THINKPAD' )

   5 - SELECT "OBJECT_NAME","OBJECT_ID" FROM "T" "SYS_ALIAS_1" (accessing
       'YTK92.YTK_THINKPAD' )


Note
-----
   - dynamic sampling used for this statement

SQL> SELECT /*+ FIRST_ROWS */ OBJECT_ID, OBJECT_NAME FROM T@YTK92
  2  WHERE OBJECT_NAME IN
  3  (
  4   SELECT TABLE_NAME FROM T1@YTK92
  5   WHERE GRANTEE IN
  6    (SELECT GRANTEE FROM T1@YTK92 WHERE TABLE_NAME = 'HELP')
  7  )
  8  AND OBJECT_NAME NOT IN (SELECT SYNONYM_NAME FROM T2);

 OBJECT_ID OBJECT_NAME
---------- ------------------------------
     29559 AW$AWCREATE
     29567 AW$AWMD
     29527 AW$EXPRESS
      3387 ODCI_SECOBJ$
      3388 ODCI_WARNINGS$
     29573 OLAPTABLEVELS
     29576 OLAPTABLEVELTUPLES
      3200 PSTUBTBL

已选择8行。


执行计划
----------------------------------------------------------
Plan hash value: 4134023224

-------------------------------------------------------------------------------------------------
| Id  | Operation         | Name        | Rows  | Bytes | Cost (%CPU)| Time     | Inst   |IN-OUT|
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |             |   113 | 10848 |    79   (3)| 00:00:01 |        |      |
|*  1 |  FILTER           |             |       |       |            |          |        |      |
|*  2 |   HASH JOIN       |             |   113 | 10848 |    23  (14)| 00:00:01 |        |      |
|   3 |    VIEW           | VW_NSO_1    |   113 |  1921 |    19  (11)| 00:00:01 |        |      |
|   4 |     REMOTE        |             |       |       |            |          |  YTK92 | R->S |
|   5 |    REMOTE         | T           |   899 | 71021 |     3   (0)| 00:00:01 |  YTK92 | R->S |
|*  6 |   INDEX RANGE SCAN| IND_T2_NAME |   210 |  3570 |     1   (0)| 00:00:01 |        |      |
-------------------------------------------------------------------------------------------------

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

   1 - filter( NOT EXISTS (SELECT /*+ */ 0 FROM "T2" "T2" WHERE "SYNONYM_NAME"=:B1))
   2 - access("OBJECT_NAME"="$nso_col_1")
   6 - access("SYNONYM_NAME"=:B1)

Remote SQL Information (identified by operation id):
----------------------------------------------------

   4 - EXPLAIN PLAN SET STATEMENT_ID='PLUS1563' INTO PLAN_TABLE@! FOR SELECT DISTINCT
       "A1"."TABLE_NAME" FROM "T1" "A2","T1" "A1" WHERE "A1"."GRANTEE"="A2"."GRANTEE" AND
       "A2"."TABLE_NAME"='HELP' (accessing 'YTK92.YTK_THINKPAD' )

   5 - SELECT "OBJECT_NAME","OBJECT_ID" FROM "T" "SYS_ALIAS_1" (accessing
       'YTK92.YTK_THINKPAD' )


Note
-----
   - dynamic sampling used for this statement

10g中,Oracle改变了策略,无论是ALL_ROWS还是FIRST_ROWS都使用了HASH JOIN作为连接方式,这种方式尤其适合通过数据库链的访问远端对象,从这里也可以看到Oracle 10g在处理远端对象方面所进行的优化。

这里没有使用SEMI-JOIN方式,但是也得到了正确的结果,这是由于Oracle在访问远端对象的时候在语句中添加了DISTINCT,从而去除了重复记录,由此可见,这个bug10.2上已经被解决了。

顺便提一下METALINK的搜索结果,这次在METALINK上倒不是找不到相关的bug,而是找到了太多类似的情况,不过每种情况Oracle并没有进行详细的分析和说明,以至于根据现象无法断定目前的bug到底属于其中的哪一个,比较类似的bug包括:3092670246976932731613041166等。没有办法根据metalink上提供的信息来确定解决方法,好在这些bug基本上都在10.1版本被fixed,基本上可以确定这个bug不会影响10g的版本。

至于解决问题的方法,其实上来在确定问题时已经相应的介绍了很多种了,只要破坏下面的任意一种情况,bug就不会出现:9IFIRST_ROWSDB_LINK访问远端对象,包含IN子查询语句。

除了这些方法外,添加HINT也是一种解决问题的方法,比如添加HASH_SJMERGE_SJNL_SJ等:

SQL> SELECT /*+ FIRST_ROWS */ OBJECT_ID, OBJECT_NAME FROM T@TEST1 T
  2  WHERE OBJECT_NAME IN
  3  (
  4   SELECT /*+ HASH_SJ */ TABLE_NAME FROM T1@TEST1
  5   WHERE GRANTEE IN
  6    (SELECT GRANTEE FROM T1@TEST1 WHERE TABLE_NAME = 'HELP')
  7  )
  8  AND OBJECT_NAME NOT IN (SELECT SYNONYM_NAME FROM T2);

 OBJECT_ID OBJECT_NAME
---------- ------------------------------
      3200 PSTUBTBL
      3387 ODCI_SECOBJ$
      3388 ODCI_WARNINGS$


执行计划
----------------------------------------------------------
   0      SELECT STATEMENT ptimizer=HINT: FIRST_ROWS (Cost=873 Card=3
          3 Bytes=3168)

   1    0   FILTER
   2    1     HASH JOIN (SEMI) (Cost=15 Card=33 Bytes=3168)
   3    2       REMOTE* (Cost=2 Card=33 Bytes=2607)                    TEST1.YTK_THINKPAD
   4    2       VIEW OF 'VW_NSO_1' (Cost=12 Card=462 Bytes=7854)
   5    4         REMOTE*                                              TEST1.YTK_THINKPAD
   6    1     INDEX (FULL SCAN) OF 'IND_T2_NAME' (NON-UNIQUE) (Cost=26
           Card=511 Bytes=8687)

 

   3 SERIAL_FROM_REMOTE            SELECT "OBJECT_NAME","OBJECT_ID" FROM "T" "S
                                   YS_ALIAS_1"

   5 SERIAL_FROM_REMOTE            SELECT /*+ HASH_SJ */ "A1"."TABLE_NAME" FROM
                                    "T1" "A1" WHERE  EXISTS (SELECT 0 F


SQL> SELECT /*+ FIRST_ROWS */ OBJECT_ID, OBJECT_NAME FROM T@TEST1 T
  2  WHERE OBJECT_NAME IN
  3  (
  4   SELECT /*+ NL_SJ */ TABLE_NAME FROM T1@TEST1
  5   WHERE GRANTEE IN
  6    (SELECT GRANTEE FROM T1@TEST1 WHERE TABLE_NAME = 'HELP')
  7  )
  8  AND OBJECT_NAME NOT IN (SELECT SYNONYM_NAME FROM T2);

 OBJECT_ID OBJECT_NAME
---------- ------------------------------
      3387 ODCI_SECOBJ$
      3388 ODCI_WARNINGS$
      3200 PSTUBTBL


执行计划
----------------------------------------------------------
   0      SELECT STATEMENT ptimizer=HINT: FIRST_ROWS (Cost=1256 Card=
          33 Bytes=3168)

   1    0   FILTER
   2    1     NESTED LOOPS (SEMI) (Cost=398 Card=33 Bytes=3168)
   3    2       REMOTE* (Cost=2 Card=33 Bytes=2607)                    TEST1.YTK_THINKPAD
   4    2       VIEW OF 'VW_NSO_1' (Cost=12 Card=462 Bytes=7854)
   5    4         REMOTE*                                              TEST1.YTK_THINKPAD
   6    1     INDEX (FULL SCAN) OF 'IND_T2_NAME' (NON-UNIQUE) (Cost=26
           Card=511 Bytes=8687)

 

   3 SERIAL_FROM_REMOTE            SELECT "OBJECT_NAME","OBJECT_ID" FROM "T" "S
                                   YS_ALIAS_1"

   5 SERIAL_FROM_REMOTE            SELECT /*+ NL_SJ */ "A1"."TABLE_NAME" FROM "
                                   T1" "A1" WHERE  EXISTS (SELECT 0 FRO

除此之外,添加DRIVING_SITE对于当前的bug也是一个不错的解决方法:

SQL> SELECT /*+ FIRST_ROWS DRIVING_SITE(T) */ OBJECT_ID, OBJECT_NAME FROM T@TEST1 T
  2  WHERE OBJECT_NAME IN
  3  (
  4   SELECT TABLE_NAME FROM T1@TEST1
  5   WHERE GRANTEE IN
  6    (SELECT GRANTEE FROM T1@TEST1 WHERE TABLE_NAME = 'HELP')
  7  )
  8  AND OBJECT_NAME NOT IN (SELECT SYNONYM_NAME FROM T2);

 OBJECT_ID OBJECT_NAME
---------- ------------------------------
      3387 ODCI_SECOBJ$
      3388 ODCI_WARNINGS$
      3200 PSTUBTBL


执行计划
----------------------------------------------------------
   0      SELECT STATEMENT (REMOTE) ptimizer=HINT: FIRST_ROWS (Cost=2
          80 Card=5 Bytes=480)

   1    0   NESTED LOOPS (Cost=280 Card=5 Bytes=480)
   2    1     VIEW OF 'VW_NSO_1' (Cost=186 Card=92 Bytes=1564)         TEST1.YANGTINGKUN
   3    2       SORT (UNIQUE)
   4    3         TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=2 Card=1 TEST1.YANGTINGKUN
           Bytes=34)
   5    4           NESTED LOOPS (Cost=186 Card=92 Bytes=6256)
   6    5             TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=2 Ca TEST1.YANGTINGKUN
          rd=92 Bytes=3128)
   7    6               INDEX (RANGE SCAN) OF 'IND_T1_NAME' (NON-UNIQU TEST1.YANGTINGKUN
          E) (Cost=1 Card=37)
   8    5             INDEX (RANGE SCAN) OF 'IND_T1_GRANTEE' (NON-UNIQ TEST1.YANGTINGKUN
          UE) (Cost=1 Card=1)
   9    1     TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=1 Card=1 Byte TEST1.YANGTINGKUN
          s=79)
  10    9       INDEX (UNIQUE SCAN) OF 'IND_T_NAME' (UNIQUE)           TEST1.YANGTINGKUN
  11   10         REMOTE* (Cost=26 Card=511 Bytes=8687)                !


  11 SERIAL_FROM_REMOTE            SELECT "SYNONYM_NAME" FROM "T2" "A2" WHERE L
                                   NNVL("SYNONYM_NAME"<>:1)

 

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/4227/viewspace-251883/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/4227/viewspace-251883/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值