SQL優化 - hint - driving_site

driving_site用於分佈式查詢中,指定數據集發送到那個數據庫上執行。在某些情況下可以大大提高SQL的性能。下面是一個小測試:
 
1. 在遠程數據庫上,創建測試表test_remote
 
pd@DWTEST>create table test_remote
  2  as
  3  select rownum rn, a.* from user_objects a;
 
Table created.
 
pd@DWTEST>insert into test_remote select * from test_remote;
 
10 rows created.
 
pd@DWTEST>/
 
20 rows created.
 
pd@DWTEST>/
 
40 rows created.
 
pd@DWTEST>/
 
...
 
655360 rows created.
 
pd@DWTEST>update test_remote set rn = rownum;
 
1310720 rows updated.
 
pd@DWTEST>commit;
 
Commit complete.
 
2. 在本地數據庫,創建測試表test_local:
 
C:\Documents and Settings\yuechao.tianyc>sqlplus test/test
 
SQL*Plus: Release 10.2.0.1.0 - Production on 星期三 4月 29 14:37:24 2009
 
Copyright (c) 1982, 2005, Oracle.  All rights reserved.
 
連接到:
 
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
 
SQL> drop table test_local purge;
 
表已刪除。
 
SQL> create table test_local
  2  as
  3  select rownum rn, a.* from user_objects a;
 
表已創建。
 
SQL> insert into test_local select * from test_local;
 
已創建48行。
 
SQL> /
...
 
已創建768行。
 
SQL> update test_local set rn = rownum;
 
已更新1536行。
 
SQL> commit;
 
提交完成。
 
3. 通過driving_site,比較數據在遠程和本地執行速度的不同:
 
-- 1. 直接執行SQL,耗時0.93m,通過執行計劃發現是將遠程表test_remote拉到本地後執行hash join的。
SQL> set timing on
SQL> set linesize 1000
SQL> set pagesize 100
SQL> explain plan for
  2  select count(*) from test_local l, test_remote@to_s12 r
  3  where l.rn = r.rn;
 
已解釋。
 
已用時間:  00: 00: 00.00
 
SQL> select count(*) from test_local l, test_remote@to_s12 r
  2  where l.rn = r.rn;
 
  COUNT(*)
----------
      1536
 
已用時間:  00: 00: 00.93
 
SQL> select * from table(dbms_xplan.display);
 
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------
Plan hash value: 2814429697
 
---------------------------------------------------------------------------------------------------
| Id  | Operation           | Name        | Rows  | Bytes | Cost (%CPU)| Time     | Inst   |IN-OUT|
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |             |     1 |    26 |    10  (10)| 00:00:01 |        |      |
|   1 |  SORT AGGREGATE     |             |     1 |    26 |            |          |        |      |
|*  2 |   HASH JOIN         |             |   327 |  8502 |    10  (10)| 00:00:01 |        |      |
|   3 |    REMOTE           | TEST_REMOTE |   327 |  4251 |     2   (0)| 00:00:01 | TO_S12 | R->S |
|   4 |    TABLE ACCESS FULL| TEST_LOCAL  |  1536 | 19968 |     7   (0)| 00:00:01 |        |      |
---------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("L"."RN"="R"."RN")
 
Remote SQL Information (identified by operation id):
----------------------------------------------------
   3 - SELECT "RN" FROM "TEST_REMOTE" "R" (accessing
       'TO_S12.REGRESS.RDBMS.DEV.US.ORACLE.COM' )
 
Note
-----
   - dynamic sampling used for this statement
 
已選擇27行。
 
已用時間:  00: 00: 00.01
 
-- 2. 通過driving_site,將本地表test_local發送到遠程執行,再將結果集返回本地。耗時0.34m
 
SQL> select/*+driving_site(r)*/ count(*) from test_local l, test_remote@to_s12 r
  2  where l.rn = r.rn;
 
  COUNT(*)
----------
      1536
 
已用時間:  00: 00: 00.34
 
SQL> explain plan for
  2  select/*+driving_site(r)*/ count(*) from test_local l, test_remote@to_s12 r
  3  where l.rn = r.rn;
 
已解釋。
 
已用時間:  00: 00: 00.14
 
SQL> select * from table(dbms_xplan.display);
 
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------
Plan hash value: 3396146028
 
------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name        | Rows  | Bytes | Cost (%CPU)| Time     | Inst   |IN-OUT|
------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT REMOTE|             |     1 |    26 |  4970   (1)| 00:01:00 |        |      |
|   1 |  SORT AGGREGATE        |             |     1 |    26 |            |          |        |      |
|*  2 |   HASH JOIN            |             |   327 |  8502 |  4970   (1)| 00:01:00 |        |      |
|   3 |    REMOTE              | TEST_LOCAL  |   327 |  4251 |     3   (0)| 00:00:01 |      ! | R->S |
|   4 |    TABLE ACCESS FULL   | TEST_REMOTE |  1130K|    14M|  4961   (1)| 00:01:00 | DWTEST |      |
------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("A2"."RN"="A1"."RN")
 
Remote SQL Information (identified by operation id):
----------------------------------------------------
   3 - SELECT "RN" FROM "TEST_LOCAL" "A2" (accessing '!' )
 
Note
-----
   - fully remote statement
   - dynamic sampling used for this statement
 
已選擇27行。
 
已用時間:  00: 00: 00.01
 
4. 通過上面的測試,可以發現二者的執行時間是不一樣的。我們再將二者分別執行100次,比較一下平均時間:
 
-- 將遠程表拉到本地執行,耗時65.71(單位爲1/100秒)
SQL> set serveroutput on
SQL> declare
  2    n_count number;
  3    n_begin_time number;
  4    n_sum_time number;
  5  begin
  6    n_sum_time := 0;
  7    for n_loop in 1..100 loop
  8      n_begin_time := dbms_utility.get_cpu_time;
  9       select count(*)
 10         into n_count
 11         from test_local l, test_remote@to_s12 r
 12        where l.rn = r.rn;
 13      n_sum_time := n_sum_time + (dbms_utility.get_cpu_time - n_begin_time);
 14    end loop;
 15    dbms_output.put_line('avg cpu_time:'||(n_sum_time/100));
 16  end;
 17  /
 
avg cpu_time:65.71
 
PL/SQL 過程已成功完成。
 
已用時間:  00: 01: 28.39
 
-- 將本地表發送到遠程執行,再將結果返回到本地,耗時0.05(單位爲1/100秒)
SQL> declare
  2    n_count number;
  3    n_begin_time number;
  4    n_sum_time number;
  5  begin
  6    n_sum_time := 0;
  7    for n_loop in 1..100 loop
  8      n_begin_time := dbms_utility.get_cpu_time;
  9       select/*+driving_site(r)*/ count(*)
 10         into n_count
 11         from test_local l, test_remote@to_s12 r
 12        where l.rn = r.rn;
 13      n_sum_time := n_sum_time + (dbms_utility.get_cpu_time - n_begin_time);
 14    end loop;
 15    dbms_output.put_line('avg cpu_time:'||(n_sum_time/100));
 16  end;
 17  /
 
avg cpu_time:.05
 
PL/SQL 過程已成功完成。
 
已用時間:  00: 00: 23.14
 
5. 結論
 
在分佈式查詢中,當一張表比較小,而且最終得到的結果集也比較小的話,使用driving_site將小表發送到大表端執行是比較快的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章