文章詳情頁(yè)
Oracle數(shù)據(jù)庫(kù)中Web分頁(yè)方法詳細(xì)介紹
瀏覽:2日期:2023-11-24 18:50:13
隨著Internet技術(shù)的發(fā)展,Web已越來(lái)越多的被應(yīng)用到各行各業(yè)。傳統(tǒng)的基于大機(jī)或C/S結(jié)構(gòu)的應(yīng)用也正逐漸的為B/S(Browser/Server)結(jié)構(gòu)所代替。而數(shù)據(jù)庫(kù),作為保存著大量信息的容器,使得Web應(yīng)用能夠提供更加豐富多彩,及時(shí)、個(gè)性化的信息。在Web應(yīng)用中,我們經(jīng)常碰到需要從數(shù)據(jù)庫(kù)搜索出滿足某個(gè)特征的數(shù)據(jù)記錄,再顯示給特定用戶。經(jīng)常這些滿足條件的記錄如此之多,一方面在同一個(gè)頁(yè)面顯示顯得異常臃腫而不切實(shí)際,另一方面用戶通常也不會(huì)對(duì)他們都感愛(ài)好,他們似乎更關(guān)心按一定規(guī)則排序出現(xiàn)在某些開始位置的若干記錄。這就要求我們對(duì)滿足條件的數(shù)據(jù)進(jìn)行分頁(yè),將用戶更關(guān)心的記錄放在首頁(yè),同時(shí)給予是否繼續(xù)瀏覽(或跳躍式閱讀)到指定頁(yè)甚至最后一頁(yè)的自由。在這里,我們希望和大家討論一下使用Oracle數(shù)據(jù)庫(kù)時(shí)的Web分頁(yè)方法。 我們說(shuō),一個(gè)好的分頁(yè)方法,它應(yīng)當(dāng)滿足以下幾個(gè)要求: 1. 數(shù)據(jù)庫(kù)處理的數(shù)據(jù)量最小; 2. 數(shù)據(jù)庫(kù)與Web應(yīng)用服務(wù)器之間的數(shù)據(jù)量傳輸最小。 假定我們有如下的業(yè)務(wù):行業(yè)產(chǎn)品表,10萬(wàn)記錄,字段包括產(chǎn)品名稱,所在行業(yè),市場(chǎng)價(jià)格。要求選擇某個(gè)行業(yè)時(shí),列出該行業(yè)下所有產(chǎn)品,并按產(chǎn)品名稱排序,超過(guò)20條的,按每頁(yè)20條分頁(yè): rudolf@TEST902>create table t nologging2 as select object_name prodUCt_name,mod(object_id,4)*10 category,3object_id price,rpad('a',300,'b') supplier4 from all_objects order by 2,15 /Table created.rudolf@TEST902>select count(*) from t;COUNT(*)----------21110用以上語(yǔ)句,我們快速生成了一個(gè)行業(yè)產(chǎn)品表,其中all_objects為Oracle的一個(gè)系統(tǒng)表(我們經(jīng)常可以使用類似的方法生成測(cè)試數(shù)據(jù))。接下來(lái),我們創(chuàng)建了索引,并為使用CBO分析了表,分析顯示該表共用去1039個(gè)數(shù)據(jù)塊: rudolf@TEST902>create index t_category_pname_ind on t (category,product_name)2 nologging3 tablespace indx4 /Index created.rudolf@TEST902>analyze table t compute statistics2 for table3 for all indexes4 for all indexed columns5 /Table analyzed.rudolf@TEST902>select table_name,blocks, empty_blocks from user_tables where table_name = 'T';TABLE_NAME BLOCKS EMPTY_BLOCKS------------------------------ ---------- ------------T1039 113為了便于討論,我們先來(lái)看一下傳統(tǒng)的做法: rudolf@TEST902>select * from2 ( select rownum rnm, a.* from3 ( select * from t where category = &category_id4 order by product_name5 ) a6 ) where rnm between &minrnm and &maxrnm7這里我們使用了三個(gè)變量,其中category_id表示用戶感愛(ài)好的行業(yè),而minrnm,maxrnm則來(lái)模擬Web程序控制分頁(yè)時(shí)傳入的最小、最大行號(hào)。我們希望選出行業(yè)為20,屬于第289頁(yè)的所有產(chǎn)品信息。我們猜測(cè)上述語(yǔ)句將按以下步驟執(zhí)行: 1. 取出所有滿足category=&category_id的記錄; 2. 按product_name進(jìn)行排序; 3. 在排序完畢的結(jié)果集中取出第&minrnm到&maxrnm記錄之間的數(shù)據(jù)。 rudolf@TEST902>set autot tracerudolf@TEST902>/Enter value for category_id: 20Enter value for minrnm: 4981Enter value for maxrnm: 500020 rows selected.Execution Plan0 SELECT STATEMENT Optimizer=FIRST_ROWS (Cost=436 Card=5263 Bytes=1094704)10 VIEW (Cost=436 Card=5263 Bytes=1094704)21 COUNT32 VIEW (Cost=436 Card=5263 Bytes=1026285)43 SORT (ORDER BY) (Cost=436 Card=5263 Bytes=1010496)54 TABLE Access (BY INDEX ROWID) OF 'T' (Cost=284 Card=5263 Bytes=1010496)65 INDEX (RANGE SCAN) OF 'T_CATEGORY_PNAME_IND' (NON-UNIQUE) (Cost=31 Card=5263)Statistics0 recursive calls0 db block gets284 consistent gets0 physical reads0 redo size1829 bytes sent via SQL*Net to client514 bytes received via SQL*Net from client3 SQL*Net roundtrips to/from client1 sorts (memory)0 sorts (disk)20 rows processed我們可以根據(jù)執(zhí)行計(jì)劃第二列的數(shù)字來(lái)閱讀計(jì)劃,即數(shù)字大的最先執(zhí)行,如“5 index (range scan)”,數(shù)字相等時(shí),按從上到下的順序執(zhí)行。上述執(zhí)行計(jì)劃顯示了與我們估計(jì)相同的順序,我們看到滿足where條件的記錄一共5263條左右(第4步中的 card=5263),它們?nèi)勘蝗〕觯⑴c排序(第3步),并在將結(jié)果集返回給用戶前,一直在處理所有的5263條記錄。然而事實(shí)上用戶似乎只關(guān)心本頁(yè)即20條記錄。顯然它與我們關(guān)于數(shù)據(jù)庫(kù)處理量最小的要求相距甚遠(yuǎn)。在分析部分,284個(gè)一致讀進(jìn)一步說(shuō)明數(shù)據(jù)庫(kù)處理了所有滿足條件的記錄(整個(gè)表占1039個(gè)數(shù)據(jù)塊,共4個(gè)擁有相近產(chǎn)品數(shù)的行業(yè),則每個(gè)行業(yè)約占259個(gè)數(shù)據(jù)塊)。 現(xiàn)在,我們把上述語(yǔ)句換成: rudolf@TEST902>select * from t2 where category = &category_id3 order by product_name4 將滿足條件的所有記錄取到客戶端(在這里為Web應(yīng)用服務(wù)器),然后利用編程語(yǔ)言對(duì)結(jié)果集分頁(yè)。以Java為例,可以使用ResultSet對(duì)象方法absolute直接定位記錄而方便地將結(jié)果集分頁(yè)。然而很顯然,它甚至滿足關(guān)于數(shù)據(jù)庫(kù)與Web應(yīng)用服務(wù)器之間的數(shù)據(jù)量傳輸最小的要求,很多情況下將明顯影響性能,嚴(yán)重時(shí)甚至?xí)?dǎo)致Web應(yīng)用服務(wù)器一端內(nèi)存溢出。言歸正傳,我們開始引入我們的方法。 方法一:同分析傳統(tǒng)做法類似,我們先列出我們的方法: rudolf@TEST902>select * from2 ( select rownum rnm, a.* from3( select * from t where category = &category_id4order by category,product_name5) a where rownum <= &maxrnm6 ) where rnm >= &minrnm7與傳統(tǒng)做法不同,我們把對(duì)最大行號(hào)的判定從第三層移到了第二層。改變雖然簡(jiǎn)單,然而它表達(dá)了一個(gè)完全不同的執(zhí)行意圖。內(nèi)部視圖: select rownum rnm, a.* from( select * from t where category = &category_idorder by category,product_name) a where rownum <= &maxrnm是8i引入的新操作,在執(zhí)行計(jì)劃中,它體現(xiàn)為stopkey。這種操作專門為提取TOP n的需求做了優(yōu)化。它需要排序字段預(yù)先建有索引,由于索引是已排序好的結(jié)構(gòu),因此取TOP n的問(wèn)題,就變?yōu)閺乃饕兄苯訌念^提取n個(gè)索引要害字,然后再根據(jù)索引就可快速的找到記錄并返回給用戶。從而有效避免了檢索全部記錄的情況。 rudolf@TEST902>set autot tracerudolf@TEST902>set verify offEnter value for category_id: 20Enter value for maxrnm: 20Enter value for minrnm: 120 rows selected.Execution Plan0 SELECT STATEMENT Optimizer=FIRST_ROWS (Cost=284 Card=20 Bytes=4160)10 VIEW (Cost=284 Card=20 Bytes=4160)21 COUNT (STOPKEY)32 VIEW (Cost=284 Card=5263 Bytes=1026285)43 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=284 Card=5263 Bytes=1010496)54 INDEX (RANGE SCAN) OF 'T_CATEGORY_PNAME_IND' (NON-UNIQUE) (Cost=31 Card=5263)Statistics0 recursive calls0 db block gets7 consistent gets0 physical reads0 redo size1848 bytes sent via SQL*Net to client514 bytes received via SQL*Net from client3 SQL*Net roundtrips to/from client0 sorts (memory)0 sorts (disk)20 rows processed應(yīng)將count(stopkey)操作與table access(by index rowid)結(jié)合起來(lái)看,這樣一來(lái),table access(by index rowid)實(shí)際上只處理了&maxrnm條記錄,這里為20條。
標(biāo)簽:
Oracle
數(shù)據(jù)庫(kù)
排行榜
