日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

oracle分页性能不同,oracle高效分页

發(fā)布時(shí)間:2025/4/16 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 oracle分页性能不同,oracle高效分页 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

什么是分頁(yè)查詢

對(duì)于基于Web的應(yīng)用而言,對(duì)查詢的結(jié)果集進(jìn)行分頁(yè)是一個(gè)比較常見的需求。假設(shè)瀏覽器界面每頁(yè)可以顯示10條記錄,最初界面顯示頭10條記錄給用戶,當(dāng)終端用戶點(diǎn)擊“下一頁(yè)”按鈕時(shí),界面顯示接下來(lái)的10條記錄。一般來(lái)說(shuō),Web后臺(tái)服務(wù)程序并不是一次性的把所有符合條件的記錄都返回給瀏覽器,再由瀏覽器應(yīng)用程序?qū)Σ樵兘Y(jié)果進(jìn)行分頁(yè)。現(xiàn)在的普遍做法都是:當(dāng)用戶要瀏覽下一頁(yè)時(shí),瀏覽器重新從WEB后臺(tái)服務(wù)器取出下10條記錄。

對(duì)于采用了數(shù)據(jù)庫(kù)的WEB應(yīng)用來(lái)說(shuō),如何對(duì)查詢的結(jié)果進(jìn)行分頁(yè)就有兩種實(shí)現(xiàn)方式,一種是WEB后臺(tái)程序把全部查詢結(jié)果取到內(nèi)存中,由它實(shí)現(xiàn)分頁(yè)。另一種是每次只從數(shù)據(jù)庫(kù)取出10條記錄,由數(shù)據(jù)庫(kù)實(shí)現(xiàn)分頁(yè)。

這兩種分頁(yè)方式各有優(yōu)缺點(diǎn),有時(shí)可能把這兩種方式結(jié)合起來(lái)應(yīng)用。在這里,我主要介紹一下如何在Oracle數(shù)據(jù)庫(kù)中實(shí)現(xiàn)分頁(yè)查詢。

如何實(shí)現(xiàn)分頁(yè)查詢

認(rèn)識(shí)ROWNUM

Oracle的ROWNUM偽列是實(shí)現(xiàn)結(jié)果集分頁(yè)的關(guān)鍵,可能有很多人對(duì)于ROWNUM偽列到底代表什么還不太清楚,有人甚至認(rèn)為它是數(shù)據(jù)庫(kù)表中記錄的編號(hào)。下面我引用在ASKTOM網(wǎng)站上的他一個(gè)例子幫助大家認(rèn)識(shí)一下ROWNUM到底為何物。為了幫助大家理解,我建了一個(gè)測(cè)試表,然后再插入20條測(cè)試數(shù)據(jù),當(dāng)前原例子中查詢語(yǔ)句表名和字段也做了相應(yīng)的修改。

--建測(cè)試表

createtable t_testrownum

( ridnumber, rvalue varchar2(30))

--插入測(cè)試數(shù)據(jù)

begin

insert into t_testrownum values(1, 'aaaa');

insert into t_testrownum values(2, 'aaaa');

insert into t_testrownum values(3, 'aaaa1');

insert into t_testrownum values(4, 'aaaa');

insert into t_testrownum values(5, 'aaaa');

insert into t_testrownum values(6, 'aaaa');

insert into t_testrownum values(7, 'aaaa');

insert into t_testrownum values(8, 'aaaa4');

insert into t_testrownum values(9, 'aaaa');

insert into t_testrownum values(10, 'aaaa');

insert into t_testrownum values(11, 'aaaa');

insert into t_testrownum values(12, 'aaaa');

insert into t_testrownum values(13, 'aaaa5');

insert into t_testrownum values(14, 'aaaa');

insert into t_testrownum values(15, 'aaaa');

insert into t_testrownum values(16, 'aaaa');

insert into t_testrownum values(17, 'aaaa');

insert into t_testrownum values(18, 'aaaa8');

insert into t_testrownum values(19, 'aaaa');

insert into t_testrownum values(20, 'aaaa');

end;

例1.

select * from t_testrownum where rownum = 1;返回結(jié)果集的第一條記錄。那么select * from T where rownum = 2;應(yīng)該返回結(jié)果集的第二條記錄。可是實(shí)際上第二個(gè)查詢語(yǔ)句不會(huì)返回任何記錄,為什么呢?

類似的例子還有:

select * from T where rownum >= 1 and rownum <= 5;返回前5條記錄,而

select * from T where rownum >= 2 and rownum <= 5;無(wú)記錄返回。

其實(shí):ROWNUM并是記錄編號(hào),而是Oracle在向外輸出結(jié)果集中的記錄時(shí)給它賦的一個(gè)順序號(hào)。當(dāng)不在查詢語(yǔ)句中限制ROWNUM時(shí),其處理邏輯如下所示:

rownum= 1

forx in ( select * from T )

loop

if ( x satisifies the predicate )

then

OUTPUT the row

rownum = rownum + 1

end if;

endloop;

當(dāng)限制ROWNUM時(shí),我們對(duì)比一下下面兩個(gè)查詢的執(zhí)行計(jì)劃:

語(yǔ)句1:select* from t_testrownum;

語(yǔ)句1的執(zhí)行計(jì)劃:

SELECT STATEMENT Optimizer Mode=CHOOSE TABLE

ACCESS FULL USDPD502.T_TESTROWNUM

語(yǔ)句2:select* from t_testrownum where rownum <= 10;

語(yǔ)句2的執(zhí)行計(jì)劃

SELECT STATEMENT Optimizer Mode=CHOOSE

COUNT STOPKEY

TABLE ACCESS FULL USDPD502.T_TESTROWNUM

通過(guò)對(duì)比,我們可以看出語(yǔ)句2的執(zhí)行計(jì)劃中增加了一條‘COUNT STOPKEY’,該句的意思是當(dāng)rownum已超出指定范圍時(shí),停止輸出,其處理邏輯如下:

rownum= 1

forx in ( select * from T )

loop

if( x satisifies the predicate )

then

OUTPUT the row

rownum= rownum + 1

endif;

if ( rownum已超出指定范圍)

then

跳出循環(huán)

endif;

endloop;

至此,我們就可以解釋上面兩個(gè)例子中的問(wèn)題了。當(dāng)我們限制rownum=1時(shí),第一條記錄滿足該條件,輸出該記錄,rownum增1,由于rownum已超出范圍,停止輸出。當(dāng)我們限制rownum=2時(shí),由于第一條記錄不滿足條件,不輸出該記錄,rownum也不增加。接著取第二條記錄,由于rownum此時(shí)還是1,不滿足條件,同樣也不輸出,如此直到遍歷全部記錄結(jié)束循環(huán)。

基本的分頁(yè)查詢

當(dāng)知道rownum是怎么回事后,我們就可以利用它來(lái)實(shí)現(xiàn)分頁(yè)查詢了。假如我們想從表T中取出第11條到第20條記錄,在未透徹了解ROWNUM之前,許多人可能會(huì)寫出下面的查詢語(yǔ)句。

--語(yǔ)句1

select* t_testrownum a where rownum >= 11 and rownum <= 20;

通過(guò)前面的分析,我們知道,這樣的寫法是錯(cuò)誤的。所以,我們把它修改為如下的寫法。

--語(yǔ)句2

select*

from( select a.*, rownum r from t_testrownum a )

wherer>= 11 and r <= 20

該語(yǔ)句的輸出結(jié)果是正確的,它的內(nèi)層查詢先從表t_testrownum中查詢出所有記錄,同時(shí)為每條記錄賦一個(gè)順序編號(hào)r,外層查詢?cè)傧拗浦贿x取編號(hào)為11到20之間的記錄。

從查詢效率上考慮一下,如果我們只需要得到第11到20條之間的記錄,那么在內(nèi)層查詢中就可以利用rownum限制內(nèi)層查詢輸出的記錄數(shù)。修改后的語(yǔ)句如下:

--語(yǔ)句3

select*

from( select a.*, rownum r

fromt_testrownum a where rownum <= 20)

wherer>= 11

需要排序的分頁(yè)查詢

有人會(huì)想,排序那還不簡(jiǎn)單嗎,加上order by子句就行了。

--語(yǔ)句4

select*

from( select a.*, rownum r from t_testrownum a where rownum <= 20 order by rvalue)

wherer>= 11

我們都知道order by是對(duì)輸出的結(jié)果集進(jìn)行排序,而不是先排序然后輸出結(jié)果集。語(yǔ)句4的實(shí)際效果是,從表t_testrownum中取出前20行記錄,然后按照rvalue字段排序,輸出排序編號(hào)大于等于11的記錄。

只對(duì)前20條記錄進(jìn)行排序顯然不是我們所期望的,為避免這個(gè)問(wèn)題,有人可能會(huì)把上面的語(yǔ)句做如下修改:

--語(yǔ)句5

select*

from( select a.*, rownum r from t_testrownum a order by rvalue)

wherer>= 11 and r <= 20

同樣,由于rownum在排序之前就確定了,我們得到得記錄并不是排序后的第11到20條記錄,而是排序前的第11到20條記錄。為得到我們期望的結(jié)果,我們必須把rownum r放到order by的外面。修改后的查詢語(yǔ)句如下。

--語(yǔ)句6

select*

from( select b.*, rownum r

from( select a.*

fromt_testrownum a order by rvalue ) b

where rownum <= 20 )

wherer>= 11

如果排序字段rvalue的值在表t_testrownum中是唯一的,那么上面的語(yǔ)句從功能實(shí)現(xiàn)上來(lái)說(shuō),就沒(méi)什么問(wèn)題了。但是如果rvalue字段的值不唯一,假設(shè)按rvalue排序后,前1到20條記錄的rvalue字段的值是相同的,我們先查出第1到10條記錄,然后再查出第11到20條記錄,這是我們會(huì)發(fā)現(xiàn),同一條記錄可能同時(shí)出現(xiàn)在這兩個(gè)查詢結(jié)果集中。這是為什么呢。一開始,我認(rèn)為是Oracle采用的排序算法是不穩(wěn)定的,兩個(gè)相同的值在兩次排序中的順序是不固定的。但是我們把語(yǔ)句select a.* from t_testrownum a order by rvalue執(zhí)行10次,卻發(fā)現(xiàn)輸出結(jié)果集的排序順序都是一致的。那么是什么導(dǎo)致排序不一致呢。為此,我們觀察了一下語(yǔ)句6的執(zhí)行計(jì)劃:

SELECT STATEMENT, GOAL = CHOOSE

VIEWObject owner=USDPD502

COUNT STOPKEY

VIEW Object owner=USDPD502

SORT ORDER BY STOPKEY

TABLE ACCESS FULL Objectowner=USDPD502 Objectname=T_TESTROWNUM

從執(zhí)行計(jì)劃中我們看出,執(zhí)行計(jì)劃的第2步是“SORT ORDER BY STOPKEY”,它表示

其并不是對(duì)所有符合條件的記錄完全排序,而是僅僅找到符合排序條件的指定條數(shù)的記錄,比如我們限制rownum <= 20,則只需找到排序在前20位的記錄。記得在Oracle的官方文檔上我曾經(jīng)見到Oracle聲稱其排序是穩(wěn)定的一致的。前面我們將select a.* from t_testrownum a order by rvalue執(zhí)行10次,發(fā)現(xiàn)排序是一致的。那么“SORT ORDER BY STOPKEY”方式的排序是否是一致的呢?我們將語(yǔ)句6執(zhí)行10次同樣發(fā)現(xiàn),其結(jié)果是一致的。那么為什么我們用語(yǔ)句6查第1到10條記錄和11到20條記錄時(shí),有些記錄為什么在這兩個(gè)查詢中出現(xiàn)的名次并不一致呢。

--語(yǔ)句7

select*

from( select a.* from t_testrownum a order by rvalue )

where rownum <= 20

--語(yǔ)句8

select*

from( select a.* from t_testrownum a order by rvalue )

where rownum <= 10

為了找出排序不一致的原因,我們分別執(zhí)行語(yǔ)句7和語(yǔ)句8,這時(shí)你會(huì)發(fā)現(xiàn),前10名的記錄在兩次查詢中并不一樣。為此,我們得出結(jié)論,當(dāng)stopkey不同時(shí),排序結(jié)果是不同的。為什么會(huì)這樣呢,大師TOM的解釋是“SORT ORDER BY STOPKEY”是Oracle為優(yōu)化TOPN(查詢排序后的前N條記錄)查詢采用的一種算法。大致的思想是:先取出為排序時(shí)前面的N條記錄,對(duì)這N條記錄排序,然后用后面的剩下的所有記錄依排序要求插入前N條記錄中。一般來(lái)說(shuō),這樣的插入排序也應(yīng)該是穩(wěn)定的,那為什么N不同,排序結(jié)果就不一樣呢?下面的兩條查詢語(yǔ)句似乎可以給你一點(diǎn)啟發(fā):

--語(yǔ)句9

selecta.*, rownum r

fromt_testrownum a

whererownum <= 10

orderby rvalue

--語(yǔ)句10

select a.*, rownum r

fromt_testrownum a

whererownum <= 20

orderby rvalue

它們的執(zhí)行計(jì)劃如下:

SELECT STATEMENT, GOAL = CHOOSE

SORT ORDER BY

COUNT STOPKEY

TABLE ACCESS FULL Object owner=USDPD502 Object name=T_TESTROWNUM

從上面兩條查詢語(yǔ)句的結(jié)果我們可以看出,排在前面的10記錄也不是一致的。要注意的是,這兩條語(yǔ)句的執(zhí)行計(jì)劃中并沒(méi)有使用“SORT ORDER BY STOPKEY”算法。而是普通的排序“SORT ORDER BY”。只是這兩次排序的記錄條數(shù)不一樣,這時(shí)有些人可能會(huì)懷疑是在排序前兩次查詢輸出記錄的順序就是不一樣的。我們可以這么測(cè)試一下,先對(duì)t_testrownum表的所有20條記錄排序,然后從表中刪除掉后10條記錄,從語(yǔ)句9和語(yǔ)句10中刪除掉where rownum <= N條件,我們發(fā)現(xiàn),查詢結(jié)果和語(yǔ)句9和語(yǔ)句10是一樣的。由此,我們可以得出結(jié)論,當(dāng)參與排序的記錄數(shù)量不同時(shí),具有相同值的記錄的排序順序是不同的。

進(jìn)行分頁(yè)查詢時(shí),如果同一條記錄在多個(gè)分頁(yè)中出現(xiàn),這樣的結(jié)果肯定不是你所期望的。為了避免這種現(xiàn)象的發(fā)生,一個(gè)簡(jiǎn)單的方法就是在排序條件中增加輔助排序字段,使得每條記錄的組合排序字段是唯一的。

如何在分頁(yè)查詢中避免排序

對(duì)于需要排序的分頁(yè)查詢來(lái)說(shuō),如果參與排序的結(jié)果集很大,而實(shí)際返回的記錄數(shù)很少,那么有兩點(diǎn)是需要注意的:第一大結(jié)果集排序?qū)ο到y(tǒng)資源的占用,第二如果排序字段的值不唯一,某些記錄會(huì)出現(xiàn)在多個(gè)分頁(yè)中。如何避免以上的兩點(diǎn)呢,我們知道,索引的鍵值是有序組織的,我們是否可以利用索引來(lái)避免排序呢。答案是肯定的,我們?cè)趓value上建立索引:

--語(yǔ)句11

createindex idx_testrownum_rvalue on t_testrownum(rvalue);

這時(shí),我們把語(yǔ)句6修改一下:

--語(yǔ)句12

select*

from( select b.*, rownum r

from( select a.*

fromt_testrownum a

wherervalue > chr(1) order by rvalue ) b

where rownum <= 20 )

wherer>= 11

執(zhí)行語(yǔ)句12,它的執(zhí)行計(jì)劃如下:

SELECT STATEMENT, GOAL = CHOOSE

VIEW Object owner=USDPD502

COUNT STOPKEY

VIEW Object owner=USDPD502

TABLE ACCESS BY INDEX ROWID Object owner=USDPD502 Object name=T_TESTROWNUM

INDEX RANGE SCAN Object owner=USDPD502 Object name=IDX_TESTROWNUM_RVALUE

從上面的執(zhí)行計(jì)劃中,我們已看不到“SORT ORDER BY STOPKEY”字樣,說(shuō)明沒(méi)有排序步驟。那么記錄在分頁(yè)中重復(fù)的問(wèn)題是否也解決了呢,經(jīng)過(guò)測(cè)試,該問(wèn)題也不復(fù)存在。

那么如果我們需要降序排序呢?對(duì)于降序排序,我們需要增加相應(yīng)的hints來(lái)提示優(yōu)化器走降序索引掃描。

-語(yǔ)句13

select *

from( select b.*, rownum r

from( select/*+index_desc(a idx_testrownum_rvalue)*/a.*

fromt_testrownum a

wherervalue > chr(1) order by rvalue desc ) b

where rownum <= 20 )

wherer>= 11

語(yǔ)句13的執(zhí)行計(jì)劃如下:

SELECT STATEMENT, GOAL = CHOOSE

VIEW Object owner=USDPD502

COUNT STOPKEY

VIEW Object owner=USDPD502

TABLE ACCESS BY INDEX ROWID Object owner=USDPD502 Object name=T_TESTROWNUM

INDEXRANGESCAN DESCENDING Objectowner=USDPD502

利用索引避免排序需要的注意點(diǎn)

雖然使用索引來(lái)避免排序是一個(gè)好方法,但是,任何事物都不可能是十全十美的,使用該方法時(shí)需要注意以下幾點(diǎn):

1)排序字段上的索引必須是升序索引,如果使用降序索引將導(dǎo)致升序排序時(shí)分頁(yè)出現(xiàn)問(wèn)題。(具體是什么原因我現(xiàn)在還沒(méi)弄明白,如果有知道原因的可以指點(diǎn)一下)

2)在分頁(yè)開始記錄數(shù)大于10000后,利用索引排序進(jìn)行分頁(yè)的性能反而不如直接排序分頁(yè)的方式好。(如果字段是數(shù)字性,性能下降不大,如果是字符串則性能下降明顯,這可能和字符串和數(shù)字的比較方式不同有關(guān))

總結(jié)

以上是生活随笔為你收集整理的oracle分页性能不同,oracle高效分页的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日日夜夜网站 | 真人毛片视频 | 污污内射久久一区二区欧美日韩 | 国产12页 | 精品亚洲一区二区三区四区五区 | 国产一区免费观看 | 成人免费毛片高清视频 | 少妇被又大又粗又爽毛片久久黑人 | 亚洲国产精品尤物yw在线观看 | 可以在线观看av的网站 | 五月天中文字幕 | 国产精品三级 | 天天综合欧美 | 大尺码肥胖女系列av | 日韩av大全| 国产精品2018 | 就是色 | 日韩午夜免费视频 | av免费播放网站 | 97潮色 | 久久欧美精品 | 日本少妇xxxx软件 | 亚洲av永久无码精品国产精品 | 丝袜毛片 | 日韩美女黄色 | 精品三级视频 | 一区视频在线 | 领导揉我胸亲奶揉下面 | 久久久久久久亚洲精品 | 国产精品av在线免费观看 | 一区二区三区影院 | www.人人干| 免费黄色入口 | 三级网站| 人人做| 国产一区免费在线观看 | 黑丝美女啪啪 | 欧美做爰xxxⅹ性欧美大片 | www.奇米 | 欧美人妻精品一区二区 | 国产真实伦对白全集 | 中文字幕成人在线 | www视频免费在线观看 | 中文字幕国产 | 国产农村妇女毛片精品久久 | 精品一区二区三区久久 | 精品欧美一区二区久久久 | 奇米影视色 | 精品欧美一区二区精品久久 | 激情 小说 亚洲 图片 伦 | 51成人精品网站 | 久久亚洲AV无码精品 | 日本午夜激情 | 中文字幕日韩精品无码内射 | 日韩精品一区二区三区不卡在线 | 最好看的2019年中文在线观看 | 国产精品久久久久影院老司 | 国产婷婷一区二区三区久久 | 久久成人福利 | avtt国产| 日韩人妻精品一区二区三区 | 97超碰人人模人人人爽人人爱 | 亚洲人成网站999久久久综合 | 中文字字幕在线中文乱码 | 800av在线视频 | 一本久道综合色婷婷五月 | 神马久久网站 | 国产资源视频 | 亚洲狼人伊人 | videos另类灌满极品另类 | jzzijzzij亚洲成熟少妇在线播放 狠狠躁日日躁夜夜躁2022麻豆 | 打屁股调教网站 | 国产黄色在线看 | 波多野结衣www | 无码一区二区三区免费 | 女攻总攻大胸奶汁(高h) | 日本黄色大片网站 | 亚洲精品国产精品乱码不99按摩 | 五月婷婷视频在线 | 国产欧美一区二区三区四区 | 有码视频在线观看 | av爱爱| 国产一区二区小说 | 国产精品又黄又爽又色无遮挡 | 天天干天天操天天插 | 日韩中字在线 | 综合久久久久久 | 日本不卡一区在线 | 黑人乱码一区二区三区av | 成人αv| 欧美成人三级在线观看 | 精品久久久久成人码免费动漫 | 久久成人激情 | 日韩激情一区二区 | 凹凸精品熟女在线观看 | 亚洲最大毛片 | 国产av电影一区二区三区 | 91亚色视频 | 中国av一级片 |