FIRST_ROWS和ALL_ROWS的區別和作用


first_rows是最佳響應速度設計的,不能說返回一條記錄,這樣說是錯誤的。

all_rows是為了最佳吞吐量,也不能說是all_rows傾向與采用全表掃描,其實默認情況下都是all_rows的。

給一個例子:

 

 

代碼:


 

SQL> create index ind_page_test_id on page_test(id);

Index created

SQL> analyze index ind_page_test_id compute statistics;

Index analyzed

SQL>select * from (

  2      select rownum rn,a.object_name

  3      from page_test a,

  4           page_test b,

  5           page_test c

  6      where a.id=b.id

  7      and b.id=c.id

  8      and rownum<=5

  9*     ) where rn>0

已用時間:  00: 00: 02.09

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2473 Card=5 Bytes=395)

   1    0   VIEW (Cost=2473 Card=5 Bytes=395)

   2    1     COUNT (STOPKEY)

   3    2       HASH JOIN (Cost=2473 Card=831104 Bytes=23270912)

   4    3         HASH JOIN (Cost=765 Card=831104 Bytes=6648832)

   5    4           INDEX (FAST FULL SCAN) OF 'IND_PAGE_TEST_ID' (NON-UNIQUE) (Cost=180 Card=831104 Bytes=3324416)

   6    4           INDEX (FAST FULL SCAN) OF 'IND_PAGE_TEST_ID' (NON-UNIQUE) (Cost=180 Card=831104 Bytes=3324416)

   7    3         TABLE ACCESS (FULL) OF 'PAGE_TEST' (Cost=1051 Card=831104 Bytes=16622080)

Statistics

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

          0  recursive calls

          0  db block gets

       3725  consistent gets

          0  physical reads

          0  redo size

          ……

SQL> select * from (

  2      select /*+ first_rows */

  3      rownum rn,a.object_name

  4      from page_test a,

  5           page_test b,

  6           page_test c

  7      where a.id=b.id

  8      and b.id=c.id

  9      and rownum<=5

10     ) where rn>0;

已用時間:  00: 00: 01.01

Execution Plan

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

   0      SELECT STATEMENT Optimizer=HINT: FIRST_ROWS (Cost=1666362 Card=5 Bytes=395)

   1    0   VIEW (Cost=1666362 Card=5 Bytes=395)

   2    1     COUNT (STOPKEY)

   3    2       NESTED LOOPS (Cost=1666362 Card=831104 Bytes=23270912)

   4    3         NESTED LOOPS (Cost=1666362 Card=831104 Bytes=19946496)

   5    4           INDEX (FULL SCAN) OF 'IND_PAGE_TEST_ID' (NON-UNIQUE) (Cost=1852 Card=831104 Bytes=3324416)

   6    4           TABLE ACCESS (BY INDEX ROWID) OF 'PAGE_TEST' (Cost=3 Card=1 Bytes=20)

   7    6             INDEX (RANGE SCAN) OF 'IND_PAGE_TEST_ID' (NON-UNIQUE) (Cost=2 Card=1)

   8    3         INDEX (RANGE SCAN) OF 'IND_PAGE_TEST_ID' (NON-UNIQUE) (Cost=2 Card=1 Bytes=4)

Statistics

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

          0  recursive calls

          0  db block gets

         35  consistent gets

          0  physical reads

          0  redo size

        

 


 

從這里我們可以看到,使用first_rows是查詢的邏輯讀降低到了只有35個,而且響應速度也變的更快,我們進一步觀察其執行時間:

 

 

代碼:


 

SQL>set autot off        

SQL>select * from (

  2      select rownum rn,a.object_name

  3      from page_test a,

  4           page_test b,

  5           page_test c

  6      where a.id=b.id

  7      and b.id=c.id

  8      and rownum<=5

  9*     ) where rn>0

     ……

已用時間:  00: 00: 01.08

SQL> select * from (

  2      select /*+ first_rows */

  3      rownum rn,a.object_name

  4      from page_test a,

  5           page_test b,

  6           page_test c

  7      where a.id=b.id

  8      and b.id=c.id

  9      and rownum<=5

10     ) where rn>0;

……

已用時間:  00: 00:

 


 

可以看到,而且實行時間幾乎為0。這個是一個比較好的結果,表示采用forst_rows提示起到了很好的效果,因為forst_rows在沒有索引的表上關聯是不合適的,而且根據forst_rows提示的功能,是為了滿足最快反應速度,也就是說對開始的頁面返回速度很快,但是對后面的行返回速度很慢,我們就來測試一下。

 

 

代碼:


 

SQL>select * from (

  2      select rownum rn,a.object_name

  3      from page_test a,

  4           page_test b,

  5           page_test c

  6      where a.id=b.id

  7      and b.id=c.id

  8      and rownum<=5005

  9*     ) where rn>5000

……

已用時間:  00: 00: 01.08

SQL> select * from (

  2      select /*+ first_rows */

  3      rownum rn,a.object_name

  4      from page_test a,

  5           page_test b,

  6           page_test c

  7      where a.id=b.id

  8      and b.id=c.id

  9      and rownum<=5005

10     ) where rn>5000;

……

已用時間:  00: 00: 00.00

SQL> select * from (

  2      select rownum rn,a.object_name

  3      from page_test a,

  4           page_test b,

  5           page_test c

  6      where a.id=b.id

  7      and b.id=c.id

  8      and rownum<=50005

  9      ) where rn>50000;

……

已用時間:  00: 00: 01.09

SQL> select * from (

  2      select /*+ first_rows */

  3      rownum rn,a.object_name

  4      from page_test a,

  5           page_test b,

  6           page_test c

  7      where a.id=b.id

  8      and b.id=c.id

  9      and rownum<=50005

10     ) where rn>50000;

……

已用時間:  00: 00: 00.07

SQL> select * from (

  2      select rownum rn,a.object_name

  3      from page_test a,

  4           page_test b,

  5           page_test c

  6      where a.id=b.id

  7      and b.id=c.id

  8      and rownum<=500005

  9      ) where rn>500000;

……

已用時間:  00: 00: 02.06

SQL> select * from (

  2      select /*+ first_rows */

  3      rownum rn,a.object_name

  4      from page_test a,

  5           page_test b,

  6           page_test c

  7      where a.id=b.id

  8      and b.id=c.id

  9      and rownum<=500005

10     ) where rn>500000;

……

已用時間:  00: 00: 07.07

.

 


 

通過不同的測試,可以看到,在開始部分,增加提示的速度明顯要比不增加提示要快,但是,隨着往后翻頁,速度會越來越慢。幸好的是,大部分的用戶只對前面的數據敢興趣,所以增加前面部分的分頁速度是很重要的。其實還可以通過程序轉換的方式,即前面的分頁查詢使用hint提示,而后面部分則使用普通的分頁查詢。或者,對於很多條記錄的分頁查詢,根本就沒有最后一頁這樣顯示最后部分的按鈕,類似google,可以一次顯示依次的10個頁面。

 

 

 

從本質上說,FIRST_ROWS和ALL_ROWS是通過提示影響Oracle執行計划的選擇,從而提供不同的查詢響應。

通常FIRST_ROWS模式下,Oracle傾向於使用NL來進行表連接,NL通過驅動表逐層析取內層表,可以邊執行邊輸出,也就實現了通常所說的,以盡快地速度返回(第一條)結果。也就是最小化立即響應時間。

而ALL_ROWS模式下,Oracle傾向於使用HASH JOIN來進行表連接,HASH JOIN需要首先在RAM中構造HASH表,返回第一條記錄必須等待這個HASH TABLE構造完畢,從而返回第一條記錄的時間會晚於NL。而ALL_ROWS通常會有更好的成本,從而可能使總體執行時間更短


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM