【實驗】where子句的解析順序及執行效率

secooler發表於2009-09-27
有一種聲音叫做:where子句的解析順序是從右向左(如果上下書寫的話,就是從下到上),因此能夠過濾掉大部分資料的條件要書寫到where子句的後面,同時具有表關聯的條件要放到where子句的前面。

這種說法在Oracle 10gR2的CBO和RBO模式下是什麼樣的呢?

這裡做一個這樣的實驗,我們在RBO和CBO兩種情況下對where子句中關於過濾記錄數有懸殊區別的兩個條件的順序調整,看一下效果。

我們能得到一個結論是:
在Oracle 10.2.0.3環境下測試,無論在RBO還是在CBO最佳化條件下沒有表連線的情況下效率是一樣的。
(由於ORACLE 的自動化最佳化策略,根據不同的資料分析結果,可能執行計劃不相同。具體以您自己的實驗資料為準,本實驗僅供參考。)

實驗參考如下。

1.測試環境是Oracle 10.2.0.3
sec@ora10g> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
PL/SQL Release 10.2.0.3.0 - Production
CORE    10.2.0.3.0      Production
TNS for Linux: Version 10.2.0.3.0 - Production
NLSRTL Version 10.2.0.3.0 - Production

2.建立包含3千萬資料的測試表
big_table的id是表的主鍵(索引可用)
@big_table 30000000

3.我們使用的兩個條件
1)符合OWNER = 'SEC'條件的記錄數大概在6萬(返回小資料量的條件)
sec@ora10g> select count(*) from big_table where WNER = 'SEC';

  COUNT(*)
----------
     54595

2)符合id > 20000000條件的記錄數為1千萬(返回大資料量的條件)
sec@ora10g> select count(*) from big_table where id > 20000000;

  COUNT(*)
----------
  10000000

4.測試場景,及測試結論
1)CBO最佳化環境下,小資料量返回條件在where子句下方(where子句的最後一個條件)
2)CBO最佳化環境下,小資料量返回條件在where子句上方(where子句的最前一個條件)
3)RBO最佳化環境下,小資料量返回條件在where子句下方(where子句的最後一個條件)
4)RBO最佳化環境下,小資料量返回條件在where子句上方(where子句的最前一個條件)

測試結論:
以上四種場景測試效率一樣。

5.具體的測試場景的展開
1)CBO最佳化環境下,小資料量返回條件在where子句下方(where子句的最後一個條件)
sec@ora10g> select count(*) from big_table
 where id >= 20000000
   and WNER = 'SEC';
  2    3
  COUNT(*)
----------
     18265

Elapsed: 00:00:04.26

Execution Plan
----------------------------------------------------------
Plan hash value: 599409829

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     1 |    23 | 89421   (1)| 00:17:54 |
|   1 |  SORT AGGREGATE    |           |     1 |    23 |            |          |
|*  2 |   TABLE ACCESS FULL| BIG_TABLE |   100K|  2255K| 89421   (1)| 00:17:54 |
--------------------------------------------------------------------------------


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

   2 - filter("OWNER"='SEC' AND "ID">=20000000)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
     405329  consistent gets
     320902  physical reads
        936  redo size
        517  bytes sent via SQL*Net to client
        492  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

2)CBO最佳化環境下,小資料量返回條件在where子句上方(where子句的最前一個條件)
sec@ora10g> select count(*) from big_table
 where WNER = 'SEC'
   and id >= 20000000;
  2    3
  COUNT(*)
----------
     18265

Elapsed: 00:00:04.27

Execution Plan
----------------------------------------------------------
Plan hash value: 599409829

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     1 |    23 | 89421   (1)| 00:17:54 |
|   1 |  SORT AGGREGATE    |           |     1 |    23 |            |          |
|*  2 |   TABLE ACCESS FULL| BIG_TABLE |   100K|  2255K| 89421   (1)| 00:17:54 |
--------------------------------------------------------------------------------


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

   2 - filter("OWNER"='SEC' AND "ID">=20000000)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
     405329  consistent gets
     320902  physical reads
        980  redo size
        517  bytes sent via SQL*Net to client
        492  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed


3)RBO最佳化環境下,小資料量返回條件在where子句下方(where子句的最後一個條件)
sec@ora10g> select /*+ RULE */ count(*) from big_table
 where id >= 20000000
   and WNER = 'SEC';
  2    3
  COUNT(*)
----------
     18265

Elapsed: 00:00:03.10

Execution Plan
----------------------------------------------------------
Plan hash value: 3098837282

-----------------------------------------------------
| Id  | Operation                    | Name         |
-----------------------------------------------------
|   0 | SELECT STATEMENT             |              |
|   1 |  SORT AGGREGATE              |              |
|*  2 |   TABLE ACCESS BY INDEX ROWID| BIG_TABLE    |
|*  3 |    INDEX RANGE SCAN          | BIG_TABLE_PK |
-----------------------------------------------------

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

   2 - filter("OWNER"='SEC')
   3 - access("ID">=20000000)

Note
-----
   - rule based optimizer used (consider using cbo)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
     157420  consistent gets
          0  physical reads
          0  redo size
        517  bytes sent via SQL*Net to client
        492  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

4)RBO最佳化環境下,小資料量返回條件在where子句上方(where子句的最前一個條件)
sec@ora10g> select /*+ RULE */ count(*) from big_table
 where WNER = 'SEC'
   and id >= 20000000;
  2    3
  COUNT(*)
----------
     18265

Elapsed: 00:00:03.09

Execution Plan
----------------------------------------------------------
Plan hash value: 3098837282

-----------------------------------------------------
| Id  | Operation                    | Name         |
-----------------------------------------------------
|   0 | SELECT STATEMENT             |              |
|   1 |  SORT AGGREGATE              |              |
|*  2 |   TABLE ACCESS BY INDEX ROWID| BIG_TABLE    |
|*  3 |    INDEX RANGE SCAN          | BIG_TABLE_PK |
-----------------------------------------------------

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

   2 - filter("OWNER"='SEC')
   3 - access("ID">=20000000)

Note
-----
   - rule based optimizer used (consider using cbo)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
     157420  consistent gets
          0  physical reads
          0  redo size
        517  bytes sent via SQL*Net to client
        492  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

6.關於複雜計算條件和關聯條件的排列組合方式,如果您有興趣,也可以進一步做一下測試。我們的原則是:用真實的實驗講話!

-- The End --

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

相關文章