【WITH Clause】使用WITH子句提高查詢統計效率-顛覆思維定勢

secooler發表於2010-03-22
這裡介紹的的是一種SQL查詢方法,顛覆您日常以select開始的SQL查詢寫法。
這種神奇的使用方法的背後隱藏著效能的提升!

我們一起來體驗一下其中的奧妙。

1.建立表T,並簡單初始化幾條資料
sec@ora10g> create table t (x number(10), y number(10));
sec@ora10g> insert into t values (1,110);
sec@ora10g> insert into t values (2,120);
sec@ora10g> insert into t values (2,80);
sec@ora10g> insert into t values (3,150);
sec@ora10g> insert into t values (3,30);
sec@ora10g> insert into t values (3,60);
sec@ora10g> commit;

sec@ora10g> select * from t;

         X          Y
---------- ----------
         1        110
         2        120
         2         80
         3        150
         3         30
         3         60

6 rows selected.

2.需求描述
按照x列分組後統計y列的總值,我們的最終目標是選出比y列總值的三分之一大的那些分組統計資訊。

3.使用子查詢方式實現
這可能是大家最容易想到的方法。
sec@ora10g> SELECT x, SUM (y) AS total_y
  2    FROM t
  3  GROUP BY x
  4  HAVING SUM (y) > (SELECT SUM (y) / 3 FROM t)
  5  ORDER BY total_y
  6  /

         X    TOTAL_Y
---------- ----------
         2        200
         3        240

4.WITH Clause方法閃亮登場
sec@ora10g> WITH secooler_sum AS (SELECT x, SUM (y) total_y
  2                          FROM t
  3                        GROUP BY x)
  4  SELECT x, total_y
  5    FROM secooler_sum
  6   WHERE total_y > (SELECT SUM (total_y) / 3 FROM secooler_sum)
  7  ORDER BY total_y
  8  /

         X    TOTAL_Y
---------- ----------
         2        200
         3        240


是不是很神奇!這裡的查詢語句不是以select開始的,而是以“WITH”關鍵字開頭。可以認為Oracle在真正進行查詢之前預先構造了一個臨時表secooler_sum,之後我們便可多次使用它做進一步的分析和處理。

5.WITH Clause方法的優點
使用WITH Clause方法有什麼好處呢?
首先,增加了SQL的易讀性,如果構造了多個子查詢,結構會更清晰;
更重要的是:“一次分析,多次使用”,這也是為什麼會提供效能的地方,達到了“少讀”的目標。

6.知其所以然
為什麼WITH Clause方法會提高效率?透過檢視上面兩種方法的執行計劃便可略知一二。
1)使用子查詢的執行計劃
sec@ora10g> set autot trace exp
sec@ora10g> SELECT x, SUM (y) AS total_y
  2    FROM t
  3  GROUP BY x
  4  HAVING SUM (y) > (SELECT SUM (y) / 3 FROM t)
  5  ORDER BY total_y
  6  /

Execution Plan
----------------------------------------------------------
Plan hash value: 4167292448

-----------------------------------------------------------------------------
| Id  | Operation            | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |     6 |   156 |     5  (40)| 00:00:01 |
|   1 |  SORT ORDER BY       |      |     6 |   156 |     5  (40)| 00:00:01 |
|*  2 |   FILTER             |      |       |       |            |          |
|   3 |    HASH GROUP BY     |      |     6 |   156 |     5  (40)| 00:00:01 |
|   4 |     TABLE ACCESS FULL| T    |     6 |   156 |     3   (0)| 00:00:01 |
|   5 |    SORT AGGREGATE    |      |     1 |    13 |            |          |
|   6 |     TABLE ACCESS FULL| T    |     6 |    78 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------

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

   2 - filter(SUM("Y")> (SELECT SUM("Y")/3 FROM "T" "T"))

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


2)使用子WITH Clause的執行計劃
sec@ora10g> WITH secooler_sum AS (SELECT x, SUM (y) total_y
  2                          FROM t
  3                        GROUP BY x)
  4  SELECT x, total_y
  5    FROM secooler_sum
  6   WHERE total_y > (SELECT SUM (total_y) / 3 FROM secooler_sum)
  7  ORDER BY total_y
  8  /

Execution Plan
----------------------------------------------------------
Plan hash value: 706070671

---------------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name                       | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |                            |     6 |   156 |     9  (23)| 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 |   SORT ORDER BY            |                            |     6 |   156 |     5  (20)| 00:00:01 |
|*  6 |    VIEW                    |                            |     6 |   156 |     2   (0)| 00:00:01 |
|   7 |     TABLE ACCESS FULL      | SYS_TEMP_0FD9D6660_23A196E |     6 |   156 |     2   (0)| 00:00:01 |
|   8 |     SORT AGGREGATE         |                            |     1 |    13 |            |          |
|   9 |      VIEW                  |                            |     6 |    78 |     2   (0)| 00:00:01 |
|  10 |       TABLE ACCESS FULL    | SYS_TEMP_0FD9D6660_23A196E |     6 |   156 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------

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

   6 - filter("TOTAL_Y"> (SELECT SUM("TOTAL_Y")/3 FROM  (SELECT /*+ CACHE_TEMP_TABLE ("T1") */
              "C0" "X","C1" "TOTAL_Y" FROM "SYS"."SYS_TEMP_0FD9D6660_23A196E" "T1") "SECOOLER_SUM"))

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


可見,第一種使用子查詢的方法T表被掃描了兩次,而使用WITH Clause方法,T表僅被掃描一次。
這也是為什麼在大型資料倉儲系統中推薦使用WITH Clause方法進行查詢統計的原因,這樣可以大大的提高資料分析和查詢的效率。

另外,觀察WITH Clause方法執行計劃,其中“SYS_TEMP_0FD9D6660_23A196E”便是在執行過程中構造的中間統計結果臨時表。

7.Oracle官方文件中有關WITH Clause的簡單描述
Computation Using the WITH Clause

The WITH clause (formally known as subquery_factoring_clause) enables you to reuse the same query block in a SELECT statement when it occurs more than once within a complex query. WITH is a part of the SQL-99 standard. This is particularly useful when a query has multiple references to the same query block and there are joins and aggregations. Using the WITH clause, Oracle retrieves the results of a query block and stores them in the user's temporary tablespace. Note that Oracle Database does not support recursive use of the WITH clause.

參考連結:

8.小結
WITH Clause方法在資料倉儲或大資料量查詢中有著自己的優勢。
一切提高效能的措施都是推崇的。靈活掌握,裨益無限。在遇到具體問題時可善加利用。

Good luck.

secooler
10.03.22

-- The End --

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

相關文章