[20140221]执行计划以及dblink.txt
--昨天我调整一个sql语句,忽略一个细节,sql里面使用了视图,视图里面使用dblink.我正是关注逻辑读不大,让我忽视了优化.
--举一些例子来说明问题.
1.建立测试环境:
SCOTT@test> @ver
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
--在本地建立一张表t.主要是为了测试的需要.
SCOTT@test> create table t as select dept_code from dept_dict@test1.com where rownumTable created.
SCOTT@test> exec dbms_stats.gather_table_stats(user, 't', method_opt => 'FOR ALL COLUMNS SIZE 1',no_invalidate=>false);
PL/SQL procedure successfully completed.
2.测试1:
SCOTT@test> select * from dept_dict@test1.com where dept_code='0202';
SCOTT@test> @dpc '' ''
PLAN_TABLE_OUTPUT
------------------------------------------
SQL_ID 4nuvmzgzyb8b5, child number 0
select * from dept_dict@test1.com where dept_code='0202'
NOTE: cannot fetch plan for SQL_ID: 4nuvmzgzyb8b5, CHILD_NUMBER: 0
Please verify value of SQL_ID and CHILD_NUMBER;
It could also be that the plan is no longer in cursor cache (check v$sql_plan)
--可以发现如果sql语句仅仅包含dblink的链接是无法看执行计划的.
SCOTT@test> set autotrace traceonly
SCOTT@test> select /*+ full(a) */ * from dept_dict@test1.com a where dept_code='0202';
Execution Plan
----------------------------------------------------------
Plan hash value: 4107200483
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Inst |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT REMOTE| | 1 | 50 | 4 (0)| 00:00:01 | |
|* 1 | TABLE ACCESS FULL | DEPT_DICT | 1 | 50 | 4 (0)| 00:00:01 | ORCL |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("A1"."DEPT_CODE"='0202')
Note
-----
- fully remote statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
1403 bytes sent via SQL*Net to client
519 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
--注意:提示写成 /*+ full(dept_dict@test1.com) */ 不行.必须使用别名.
--可以发现远端执行的是全表扫描,但是记录的逻辑读是0,
--如果查询远端实际上执行的是
JSJS@209> @dpc 21p6sd8a4pz7m ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID 21p6sd8a4pz7m, child number 0
-------------------------------------
SELECT /*+ FULL ("A1") */ "A1"."SERIAL_NO","A1"."DEPT_CODE","A1"."DEPT_N
AME","A1"."DEPT_ALIAS","A1"."CLINIC_ATTR","A1"."OUTP_OR_INP","A1"."INTER
NAL_OR_SERGERY","A1"."INPUT_CODE","A1"."RECKON_UNIT_OUTP","A1"."RECKON_U
NIT_INP","A1"."DEPT_INTRODUCTION","A1"."DEPT_ADDRESS" FROM "DEPT_DICT"
"A1" WHERE "A1"."DEPT_CODE"='0202'
Plan hash value: 4107200483
-------------------------------------------------------------
| Id | Operation | Name | E-Rows | Cost (%CPU)|
-------------------------------------------------------------
|* 1 | TABLE ACCESS FULL| DEPT_DICT | 1 | 4 (0)|
-------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("A1"."DEPT_CODE"='0202')
3.测试2:
--加入一张本地表:
SCOTT@test> select * from t where dept_code in (select /*+ full(a) */ dept_code from dept_dict@test1.com a where dept_code='010101');
DEPT_COD
--------
010101
SCOTT@test> @dpc '' ''
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------
SQL_ID a2cd5qp3dfk4j, child number 0
-------------------------------------
select * from t where dept_code in (select /*+ full(a) */ dept_code
from dept_dict@test1.com a where dept_code='010101')
Plan hash value: 2256468146
--------------------------------------------------------------
| Id | Operation | Name | E-Rows | Cost (%CPU)|
--------------------------------------------------------------
| 0 | SELECT STATEMENT | | | 7 (100)|
| 1 | NESTED LOOPS | | 1 | 7 (0)|
| 2 | REMOTE | DEPT_DICT | 1 | 4 (0)|
|* 3 | TABLE ACCESS FULL| T | 1 | 3 (0)|
--------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("DEPT_CODE"='010101')
SCOTT@test> set autotrace traceonly
SCOTT@test> select * from t where dept_code in (select /*+ full(a) */ dept_code from dept_dict@test1.com a where dept_code='010101');
Execution Plan
----------------------------------------------------------
Plan hash value: 2256468146
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Inst |IN-OUT|
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 12 | 7 (0)| 00:00:01 | | |
| 1 | NESTED LOOPS | | 1 | 12 | 7 (0)| 00:00:01 | | |
| 2 | REMOTE | DEPT_DICT | 1 | 6 | 4 (0)| 00:00:01 | TEST1 | R->S |
|* 3 | TABLE ACCESS FULL| T | 1 | 6 | 3 (0)| 00:00:01 | | |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("DEPT_CODE"='010101')
Remote SQL Information (identified by operation id):
----------------------------------------------------
2 - SELECT /*+ FULL ("A") */ "DEPT_CODE" FROM "DEPT_DICT" "A" WHERE
"DEPT_CODE"='010101' (accessing 'TEST1.COM' )
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
531 bytes sent via SQL*Net to client
519 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
--逻辑读仅仅为3,这并不包括远程访问的逻辑读.不过set autotrace traceonly看有一个好处,显示了远端的执行语句实际是:
2 - SELECT /*+ FULL ("A") */ "DEPT_CODE" FROM "DEPT_DICT" "A" WHERE
"DEPT_CODE"='010101' (accessing 'TEST1.COM' )
--单独访问远端表是没有这个内容的.
--实际上这个信息记录在v$sql_plan视图的other字段.这样调用dbms_xplan.display_cursor应该可以看到远端的执行计划:
SCOTT@test> column other format a100
SCOTT@test> select other,other_tag from v$sql_plan where sql_id='a2cd5qp3dfk4j' and object_type='REMOTE';
OTHER OTHER_TAG
---------------------------------------------------------------------------------------------------- --------------------
SELECT /*+ FULL ("A") */ "DEPT_CODE" FROM "DEPT_DICT" "A" WHERE "DEPT_CODE"='010101' SERIAL_FROM_REMOTE
我的dpc.sql脚本如下:
$ cat dpc.sql
set verify off
select * from table(dbms_xplan.display_cursor(NVL('&1',NULL),NULL,'ALLSTATS LAST PEEKED_BINDS &2 cost'));
--看了一下文档,看来要在加入all参数.
--- 'ALL': Maximum user level, like typical with additional
--- informations (PROJECTION, ALIAS and information about
--- REMOTE SQL if the operation is distributed).
SCOTT@test> @dpc '' all
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID a2cd5qp3dfk4j, child number 0
-------------------------------------
select * from t where dept_code in (select /*+ full(a) */ dept_code
from dept_dict@test1.com a where dept_code='010101')
Plan hash value: 2256468146
-------------------------------------------------------------------------------------------------
| Id | Operation | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time | Inst |IN-OUT|
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 7 (100)| | | |
| 1 | NESTED LOOPS | | 1 | 12 | 7 (0)| 00:00:01 | | |
| 2 | REMOTE | DEPT_DICT | 1 | 6 | 4 (0)| 00:00:01 | TEST1 | R->S |
|* 3 | TABLE ACCESS FULL| T | 1 | 6 | 3 (0)| 00:00:01 | | |
-------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$5DA710D3
2 - SEL$5DA710D3 / A@SEL$2
3 - SEL$5DA710D3 / T@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("DEPT_CODE"='010101')
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - "DEPT_CODE"[VARCHAR2,8]
2 - "DEPT_CODE"[VARCHAR2,8]
3 - "DEPT_CODE"[VARCHAR2,8]
Remote SQL Information (identified by operation id):
----------------------------------------------------
2 - SELECT /*+ FULL ("A") */ "DEPT_CODE" FROM "DEPT_DICT" "A" WHERE
"DEPT_CODE"='010101' (accessing 'TEST1.COM' )
--这样就可以看到远端执行的sql语句,优化变得很容易.
--我遇到的问题实际上隐式转换的问题,问题语句使用绑定变量,看语句很难发现问题.修改上面的例子看看.
SCOTT@test> select * from t where dept_code in (select /*+ full(a) */ dept_code from dept_dict@test1.com a where dept_code=010101);
DEPT_COD
--------
010101
SCOTT@test> @dpc '' all
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID 6k6aybav5pgnr, child number 0
-------------------------------------
select * from t where dept_code in (select /*+ full(a) */ dept_code
from dept_dict@test1.com a where dept_code=010101)
Plan hash value: 2085754
----------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time | Inst |IN-OUT| OMem | 1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 8 (100)| | | | | | |
|* 1 | HASH JOIN | | 1 | 12 | 8 (13)| 00:00:01 | | | 1306K| 1306K| 420K (0)|
| 2 | REMOTE | DEPT_DICT | 1 | 6 | 4 (0)| 00:00:01 | TEST1 | R->S | | | |
| 3 | TABLE ACCESS FULL| T | 10 | 60 | 3 (0)| 00:00:01 | | | | | |
----------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$5DA710D3
2 - SEL$5DA710D3 / A@SEL$2
3 - SEL$5DA710D3 / T@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("DEPT_CODE"="DEPT_CODE")
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - (#keys=1) "DEPT_CODE"[VARCHAR2,8]
2 - "DEPT_CODE"[VARCHAR2,8]
3 - "DEPT_CODE"[VARCHAR2,8]
Remote SQL Information (identified by operation id):
----------------------------------------------------
2 - SELECT /*+ FULL ("A") */ "DEPT_CODE" FROM "DEPT_DICT" "A" WHERE TO_NUMBER("DEPT_CODE")=010101 (accessing
'TEST1.COM' )
--在远端执行的sql语句如下:
2 - SELECT /*+ FULL ("A") */ "DEPT_CODE" FROM "DEPT_DICT" "A" WHERE TO_NUMBER("DEPT_CODE")=010101 (accessing 'TEST1.COM' )
--很明显,连接的表建立一个函数索引就解决了或者修改sql代码.