with as 查詢效能記載

dotaddjj發表於2011-10-21

With as短語也叫做子查詢部分,定義一個sql片斷,該sql片斷會被整個sql語句所用到。

With as 查詢在有的時候,是為了讓SQL語句的可讀性更高些,有的時候也可以大幅提高sql的查詢時間。

對於sql中需要重複查詢的表可以使用WITH AS短語,則只要執行一遍即可。如果WITH AS短語所定義的表名被呼叫兩次以上,則最佳化器會自動將WITH AS短語所獲取的資料放入一個TEMP表裡,如果只是被呼叫一次,則不會。

而提示materialize則是強制將WITH AS短語裡的資料放入一個全域性臨時表裡。很多查詢透過這種方法都可以提高速度。


with as
查詢特別對於UNION ALL比較有用。做報表時很有可能需要union all同一個表來分列顯示資料資訊,而union all 表的名稱又相同,如果不使用with asoracle會重複掃描相同的表,而對於sql的調整方面減少查詢明顯可以提高sql的執行效率。

做個測試來看看實際執行效果:

create table t (x number(10), y number(10));

建立一個t_sequence序列

create sequence t_sequence

increment by 1

start with 1

maxvalue 9999

cycle

nocache

t表中插入1W條資料

declare

i number;

begin

for i in 1..10000 loop

insert into t values(t_sequence.currval,t_sequence.nextval);

commit;

end loop;

end;

例如此時需要查詢按x分組的y的總和在y的總數的1/3以上和1/2以下的分組資訊

Select x,sum(y) cn from t

Group by x

Having sum(y)>(select 1/3*sum(y) from t) and sum(y)

可能一般都會這麼去寫,實際可以看出對錶執行了三個全表掃描

With s as

(select x,sum(y) cn from t

group by x)

Select x,sum(y) from s

Where cn> (select 1/3*sum(cn) from s) and cn

看看兩個sql的執行計劃吧。

SQL> Select x,sum(y) cn from t

2 Group by x

3 Having sum(y)>(select 1/3*sum(y) from t) and sum(y)

4 ;

已用時間: 00: 00: 00.56

執行計劃

----------------------------------------------------------

Plan hash value: 3810713582

------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 6 | 156 | 4 (25)| 00:00:01 |

|* 1 | FILTER | | | | | |

| 2 | HASH GROUP BY | | 6 | 156 | 4 (25)| 00:00:01 |

| 3 | TABLE ACCESS FULL | T | 6 | 156 | 3 (0)| 00:00:01 |

| 4 | SORT AGGREGATE | | 1 | 13 | | |

| 5 | TABLE ACCESS FULL | T | 6 | 78 | 3 (0)| 00:00:01 |

| 6 | SORT AGGREGATE | | 1 | 13 | | |

| 7 | TABLE ACCESS FULL| T | 6 | 78 | 3 (0)| 00:00:01 |

------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter(SUM("Y")> (SELECT .333333333333333333333333333333333333333

3*SUM("Y") FROM "T" "T") AND SUM("Y")< (SELECT .5*SUM("Y") FROM "T

"

"T"))

Note

-----

- dynamic sampling used for this statement

統計資訊

----------------------------------------------------------

315 recursive calls

0 db block gets

107 consistent gets

14 physical reads

0 redo size

499 bytes sent via SQL*Net to client

385 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

4 sorts (memory)

0 sorts (disk)

2 rows processed

SQL> alter system flush buffer_cache;

系統已更改。

已用時間: 00: 00: 00.01

SQL> alter system flush shared_pool;

系統已更改。

已用時間: 00: 00: 00.04

SQL> With s as

2 (select x,sum(y) cn from t

3 group by x)

4 Select x,cn from s

5 Where cn> (select 1/3*sum(cn) from s) and cn

已用時間: 00: 00: 02.26

執行計劃

----------------------------------------------------------

Plan hash value: 2829026223

--------------------------------------------------------------------------------

------------------------

| Id | Operation | Name | Rows | Bytes |

Cost (%CPU)| Time |

--------------------------------------------------------------------------------

------------------------

| 0 | SELECT STATEMENT | | 6 | 156 |

10 (10)| 00:00:01 |

| 1 | TEMP TABLE TRANSFORMATION | | | |

| |

| 2 | LOAD AS SELECT | | | |

| |

| 3 | HASH GROUP BY | | 6 | 156 |

4 (25)| 00:00:01 |

| 4 | TABLE ACCESS FULL | T | 6 | 156 |

3 (0)| 00:00:01 |

|* 5 | VIEW | | 6 | 156 |

2 (0)| 00:00:01 |

| 6 | TABLE ACCESS FULL | SYS_TEMP_0FD9D660B_2C190C | 6 | 156 |

2 (0)| 00:00:01 |

| 7 | SORT AGGREGATE | | 1 | 13 |

| |

| 8 | VIEW | | 6 | 78 |

2 (0)| 00:00:01 |

| 9 | TABLE ACCESS FULL | SYS_TEMP_0FD9D660B_2C190C | 6 | 156 |

2 (0)| 00:00:01 |

| 10 | SORT AGGREGATE | | 1 | 13 |

| |

| 11 | VIEW | | 6 | 78 |

2 (0)| 00:00:01 |

| 12 | TABLE ACCESS FULL | SYS_TEMP_0FD9D660B_2C190C | 6 | 156 |

2 (0)| 00:00:01 |

--------------------------------------------------------------------------------

------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

5 - filter("CN"> (SELECT .3333333333333333333333333333333333333333*SUM("CN")

FROM (SELECT

/*+ CACHE_TEMP_TABLE ("T1") */ "C0" "X","C1" "CN" FROM "SYS"."SYS_

TEMP_0FD9D660B_2C190C" "T1")

"S") AND "CN"< (SELECT .5*SUM("CN") FROM (SELECT /*+ CACHE_TEMP_T

ABLE ("T1") */ "C0" "X","C1"

"CN" FROM "SYS"."SYS_TEMP_0FD9D660B_2C190C" "T1") "S"))

Note

-----

- dynamic sampling used for this statement

統計資訊

----------------------------------------------------------

2819 recursive calls

11 db block gets

1136 consistent gets

143 physical reads

1428 redo size

499 bytes sent via SQL*Net to client

385 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

49 sorts (memory)

0 sorts (disk)

2 rows processed

t表插入40W資料

declare

i number;

begin

for i in 1..400000 loop

insert into t values(t_sequence.currval,t_sequence.nextval);

commit;

end loop;

end;

T表的資料量有40w左右

SQL> select x,sum(y) from t group by x

2 having sum(y)>(select sum(y)*1/3 from t) and sum(y)

3 ;

未選定行

已用時間: 00: 00: 02.69

執行計劃

----------

統計資訊

----------------------------------------------------------

336 recursive calls

1 db block gets

1774 consistent gets

766 physical reads

176 redo size

323 bytes sent via SQL*Net to client

374 bytes received via SQL*Net from client

1 SQL*Net roundtrips to/from client

4 sorts (memory)

0 sorts (disk)

0 rows processed

SQL> alter system flush buffer_cache;

系統已更改。

已用時間: 00: 00: 00.07

SQL> With s as

2 (select x,sum(y) cn from t

3 group by x)

4 Select x,cn from s

5 Where cn> (select 1/3*sum(cn) from s) and cn

未選定行

已用時間: 00: 00: 01.26

執行計劃

---------

711 recursive calls

30 db block gets

1267 consistent gets

806 physical reads

1428 redo size

319 bytes sent via SQL*Net to client

374 bytes received via SQL*Net from client

1 SQL*Net roundtrips to/from client

11 sorts (memory)

0 sorts (disk)

0 rows processed

t表資料量第一種查詢對錶T進行了三次全掃描,由於t表資料量比較小,而全表掃描的影響對這個查詢效率影響不大,而常規的生產庫中資料量肯定不是這個數量級的,一旦資料量增大,全表掃描消耗對整個系統的消耗那是很可怕的

(其實檢視user_segments中關於T表段的bytes也只有6M),常規的查詢對錶的掃描所消耗的資源已經不可忽視,採取with as查詢靈活運用with as建立臨時表,這也是為什麼在大型資料倉儲系統中推薦使用WITH Clause方法進行查詢統計的原因,這樣可以大大的提高資料分析和查詢的效率。

[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25362835/viewspace-1055856/,如需轉載,請註明出處,否則將追究法律責任。

相關文章