大數(shù)據(jù)分頁實(shí)現(xiàn)與性能優(yōu)化
當(dāng)前位置:點(diǎn)晴教程→知識管理交流
→『 技術(shù)文檔交流 』
摘要:Web 應(yīng)用程序中經(jīng)常使用數(shù)據(jù)分頁技術(shù),該技術(shù)是提高海量數(shù)據(jù)訪問性能的主要手段。實(shí)現(xiàn)web數(shù)據(jù)分頁有多種方案,本文通過實(shí)際項(xiàng)目的測試,對多種數(shù)據(jù)分頁方案深入分析和比較,找到了一種更優(yōu)的數(shù)據(jù)分頁方案Row_number()二分法。它依靠二分思想,將整個(gè)待查詢記錄分為2部分,使掃描的記錄量減少一半,進(jìn)而還通過對數(shù)據(jù)表及查詢條件進(jìn)行優(yōu)化,實(shí)現(xiàn)了存儲過程的優(yōu)化。根據(jù)Row_number()函數(shù)的特性,該方案不依賴于主鍵或者數(shù)字字段,大大提高了它在實(shí)際項(xiàng)目中的應(yīng)用,使大數(shù)據(jù)的分頁效率得到了更顯著的提高。 在web應(yīng)用程序開發(fā)過程中,不可避免的要頻繁查詢數(shù)據(jù)庫中的數(shù)據(jù)。隨著互聯(lián)網(wǎng)的飛速發(fā)展,中大型系統(tǒng)的數(shù)據(jù)量變得龐大而復(fù)雜,要提高系統(tǒng)的響應(yīng)性能,就需要降低客服端和服務(wù)器端數(shù)據(jù)的傳輸量,因此大數(shù)據(jù)分頁的功能不可或缺。若選擇一個(gè)不合理的數(shù)據(jù)分頁方案,大數(shù)據(jù)在查詢時(shí)就會引發(fā)網(wǎng)絡(luò)資源嚴(yán)重浪費(fèi)【1】,網(wǎng)站擁堵,查詢界面等待時(shí)間過長等一系列嚴(yán)重影響系統(tǒng)性能的問題。所以,一個(gè)有效的大數(shù)據(jù)分頁方案對于系統(tǒng)的性能而言至關(guān)重要。解決大數(shù)據(jù)分頁的問題,不同的人會采用不同的方法,其訪問性能各有優(yōu)劣。筆者通過比較多種分頁研究方案【2】,根據(jù)實(shí)際案例的測試結(jié)果,綜合分析各種分頁方案的利弊,揚(yáng)長避短,最終找到一種更優(yōu)于以往的分頁方案,Row_number()二分法。二分思想在計(jì)算機(jī)中早有應(yīng)用,二分查找算法就是二分思想的具體體現(xiàn),將它引入到存儲過程中,依靠二分法的思想,對Row_number()存儲過程分頁進(jìn)行優(yōu)化設(shè)計(jì),從而加快查詢速度,提高大數(shù)據(jù)的分頁效率。 1、動(dòng)態(tài)網(wǎng)頁數(shù)據(jù)分頁 Web數(shù)據(jù)分頁是基于降低數(shù)據(jù)傳輸量來提高服務(wù)響應(yīng)時(shí)間的分頁方法。但是不同的數(shù)據(jù)分頁方法,帶給Web主機(jī)的系統(tǒng)I/O訪問性能是不同的。無論是JAVA平臺,還是.NET平臺,對數(shù)據(jù)的分頁都提供了多種方法,主要分為2大類:一類是內(nèi)存數(shù)據(jù)分頁,一類是數(shù)據(jù)源分頁。 1.1內(nèi)存數(shù)據(jù)分頁 所謂內(nèi)存數(shù)據(jù)分頁【3】就是當(dāng)客戶端向 Web服務(wù)器發(fā)出查詢請求時(shí),Web 服務(wù)器響應(yīng)請求并構(gòu)建 SQL 語句發(fā)送到數(shù)據(jù)庫服務(wù)器,數(shù)據(jù)庫服務(wù)器執(zhí)行 SQL 語句并返回整個(gè)結(jié)果集給 Web 服務(wù)器,Web 服務(wù)器再執(zhí)行內(nèi)存數(shù)據(jù)分頁操作并把該頁數(shù)據(jù)發(fā)往客戶端,完成一次查詢。內(nèi)存數(shù)據(jù)分頁的流程如圖1所示: 圖1內(nèi)存數(shù)據(jù)分頁 內(nèi)存數(shù)據(jù)分頁的優(yōu)點(diǎn)是編程上容易實(shí)現(xiàn),對于少量數(shù)據(jù)檢索效率高,能提高開發(fā)者開發(fā)的效率。缺點(diǎn)是使用內(nèi)存數(shù)據(jù)分頁機(jī)制時(shí),首先需要把所有的數(shù)據(jù)庫記錄調(diào)入內(nèi)存。調(diào)入數(shù)萬條記錄進(jìn)入內(nèi)存本身需要消耗大量時(shí)間,所以當(dāng)數(shù)據(jù)量超過百萬時(shí),數(shù)據(jù)訪問性能急劇下降,幾乎讓W(xué)eb服務(wù)器的系統(tǒng)I/O不堪重負(fù),對于大型系統(tǒng)而言,內(nèi)存數(shù)據(jù)分頁不能滿足基本性能的要求。 對于內(nèi)存數(shù)據(jù)分頁,在.NET平臺下常用的分頁方案是GridView控件自帶的分頁【4】,GridView是DataGrid的后繼控件, GridView和DataGrid功能相似,都是在web頁面中顯示數(shù)據(jù)源中的數(shù)據(jù),將數(shù)據(jù)源中的一行數(shù)據(jù),也就是一條記錄,顯示為在web頁面上輸出表格中的一行。GridView控件功能強(qiáng)大,對于分頁操作簡單容易。 利用GridView控件自帶的分頁功能實(shí)質(zhì)是把查詢的所有數(shù)據(jù)從后臺讀取出來,然后通過內(nèi)存分頁的方式返回單頁數(shù)據(jù),因此第一頁和最后一頁的顯示速度基本相同。常用的查詢語句為:Select * from @TableName. 1.2數(shù)據(jù)源分頁 數(shù)據(jù)源分頁【4】是在數(shù)據(jù)庫服務(wù)器上實(shí)現(xiàn)截取請求頁數(shù)據(jù)的分頁操作,在 Web 服務(wù)器上無需做分頁操作。數(shù)據(jù)源分頁一般采用存儲過程[5]的方式,由于存儲過程是在數(shù)據(jù)庫服務(wù)器中預(yù)先編譯的,訪問存儲過程時(shí)只需給出存儲過程名及參數(shù)即可,往返的數(shù)據(jù)量非常小安全性也更高。數(shù)據(jù)源分頁機(jī)制的執(zhí)行流程如圖 2所示。客戶端向 Web服務(wù)器發(fā)出查詢請求,Web 服務(wù)器響應(yīng)請求,通過連接到服務(wù)器數(shù)據(jù)庫執(zhí)行存儲過程,同時(shí)返回請求頁記錄給 Web 服務(wù)器,Web 服務(wù)器再把該頁數(shù)據(jù)發(fā)往客戶端,完成一次查詢。 圖2 數(shù)據(jù)源分頁 數(shù)據(jù)源分頁的優(yōu)點(diǎn)是減輕 Web 服務(wù)器和數(shù)據(jù)庫服務(wù)器的負(fù)擔(dān),在大數(shù)的處理上保證了高效率的分頁功能。缺點(diǎn)是分頁方法必須由開發(fā)人員編程實(shí)現(xiàn),過程較為復(fù)雜。 對于數(shù)據(jù)源分頁,人們提出了使用臨時(shí)表或表變量的方法來提升訪問主鍵字段的效率,其效率也相當(dāng)高。目前常用到的數(shù)據(jù)源分頁方案有如下五種:首先說明幾個(gè)變量:@ PageSize表示分頁大小,默認(rèn)值為10;@TableName表示分頁表的名稱;@ IDField表示分頁表的排序字段;@ PageIndex表示當(dāng)前為第幾個(gè)分頁,默認(rèn)值為1。 1、Select top and Not in分頁:此分頁方案的基本思想就是利用id自增數(shù)字字段連續(xù)不間斷時(shí)通過分頁傳遞的參數(shù)實(shí)現(xiàn)分頁信息的顯示,其通用的存儲過程寫法為:SelectTop @PageSize* from @TableNamewhere(@ IDField not in (SelectTop @PageSize* (@PageIndex-1) @ IDField from @TableName order by @IDField))order by @IDField. 2、Select top and Max()分頁:根據(jù)Max()函數(shù)的性質(zhì),在分頁時(shí)依賴于數(shù)據(jù)表的id自增數(shù)字段,首先得到排序后的id記錄值;然后利用Max()來得到待分頁需要的最大記錄;最后根據(jù)id值得到分頁記錄信息。這種方式避免了全表掃描的大量I/O操作,其效率相當(dāng)高。 其通用的存儲過程寫法為:select top '+str(@pageSize)+' * From @TableName where (@ IDField >(select max(@ IDField) From (select top '+str(@pageSize*@pageIndex)+' @ IDField From @TableName order by @ IDField asc) as TempTable)) order by @ IDField asc . 3、Row_number()分頁:Row_number()函數(shù)是sql sever2005數(shù)據(jù)庫推出的新功能函數(shù),它的功能是返回結(jié)果集分區(qū)內(nèi)行的序列號,每個(gè)分區(qū)的第一行從 1 開始。其分頁存儲過程寫法為:select* from (select*,Row_Number() over(orderby @IDField) asRowNumber from @TableName ) asTempTable where RowNumber between (@ PageIndex - 1) * @ PageSize + 1 and @PageIndex* @ PageSize. 4、游標(biāo)分頁:游標(biāo)提供了一種對從表中檢索出的數(shù)據(jù)進(jìn)行操作的靈活手段,就本質(zhì)而言,游標(biāo)實(shí)際上是一種能從包括多條數(shù)據(jù)記錄的結(jié)果集中每次提取一條記錄的機(jī)制。游標(biāo)總是與一條TSQL 選擇語句相關(guān)聯(lián)因?yàn)橛螛?biāo)由結(jié)果集(可以是零條、一條或由相關(guān)的選擇語句檢索出的多條記錄)和結(jié)果集中指向特定記錄的游標(biāo)位置組成。其通用的存儲過程寫法為:declare @P1 int, --P1是游標(biāo)的id,@rowcount int,@str=’select * from @TableName’,exec sp_cursoropen @P1 output,@str,@scrollopt=1,@ccopt=1,@rowcount=@rowcount output,set @ PageIndex=(@PageIndex-1)*@pagesize+1,exec sp_cursorfetch @P1,16, @ PageIndex,@pagesize,exec sp_cursorclose @P1. 5、selectMax()結(jié)合臨時(shí)表:臨時(shí)表【6】是一種因?yàn)闀簳r(shí)需要而創(chuàng)建的數(shù)據(jù)表,主要用來臨時(shí)存儲數(shù)據(jù)處理的中間結(jié)果。利用該方案的優(yōu)點(diǎn)是可以擺脫對于數(shù)字字段的依賴,能夠更方便的應(yīng)用于實(shí)際項(xiàng)目的分頁。其通用存儲過程的語句為:declare @indextable table(id int identity(1,1),nid int) --定義表變量insert into @indextable(nid) select @IDField From @TableName order by @IDField asc;select top (@pageSize) * from @TableName O,@indextable t whereO.bid=t.nid and (id>(select max(id) From(selecttop(@pageSize*@pageIndex) id From @indextable order by id asc) as TempTable)) order by id asc. 1.3 ASP.NET實(shí)現(xiàn)數(shù)據(jù)源分頁的調(diào)用 利用ASP.NET提供的DataSet類可輕松的實(shí)現(xiàn)數(shù)據(jù)源分頁方案的調(diào)用,調(diào)用存儲過程核心代碼如下:
1.4現(xiàn)有分頁方案的不足 對于上述方案中的select top and NotIn和select top and Max()分頁方案,在實(shí)際的項(xiàng)目中很難應(yīng)用。根據(jù)NotIn()和max()函數(shù)的分頁原理,可以發(fā)現(xiàn)這兩種分頁方案存在致命的不足,就是依賴于數(shù)據(jù)表里的id自增數(shù)字字段,并且這些自增數(shù)字必須要具有連續(xù)性,如果刪除數(shù)據(jù)表里的一條或多條數(shù)據(jù),id數(shù)字字段不再連續(xù),那樣分頁的每一頁數(shù)量就會變得大小不一,這種嚴(yán)格依賴于id自增數(shù)字字段的分頁方案適用性差,對于數(shù)據(jù)表中沒有數(shù)字字段或主鍵不能按數(shù)字大小排序的分頁更是一籌莫展,所以,這樣的分頁方案局限性大,不能廣泛應(yīng)用實(shí)際項(xiàng)目。而內(nèi)存分頁GridView和傳統(tǒng)的游標(biāo)分頁在大數(shù)據(jù)的分頁上更是嚴(yán)重耗時(shí),不能達(dá)到實(shí)際網(wǎng)頁響應(yīng)的時(shí)間要求。對于max()結(jié)合臨時(shí)表這種適應(yīng)性強(qiáng)的分頁方案,在后期大數(shù)據(jù)的處理上難以保證時(shí)間的效率,隨著數(shù)據(jù)量的不斷增大,在構(gòu)建中間臨時(shí)表的時(shí)候,插入主鍵列數(shù)據(jù)到臨時(shí)表時(shí)就會用去越來越多的時(shí)間,同時(shí),又額外的開銷了臨時(shí)表和數(shù)據(jù)表匹配的時(shí)間。同max()結(jié)合臨時(shí)表一樣,Row_number()函數(shù)在大數(shù)據(jù)后期分頁時(shí)顯示的效率也并不理想,這兩種分頁方案更適用于中小型的數(shù)據(jù)分頁,要保證大數(shù)據(jù)的分頁效率,就需要用到新的分頁方案,Row_number()二分法。 2、Row_number()二分法簡介與優(yōu)化 2.1簡介 Row_number()二分法利用二分法的設(shè)計(jì)思想,此方法最大的特點(diǎn)在于它縮小了查詢時(shí)數(shù)據(jù)掃描的范圍。由于需要返回查詢結(jié)果的記錄數(shù),若利用select@ RecordCount=count(* ) from +@ Ta-bleName+@ strWhere0語句返回記錄數(shù),進(jìn)行大數(shù)據(jù)量查詢統(tǒng)計(jì)時(shí)這個(gè)語句將耗費(fèi)大量時(shí)間,這會降低系統(tǒng)分頁的性能。所以,為了避免統(tǒng)計(jì)記錄帶來的系統(tǒng)整體性能的下降,將統(tǒng)計(jì)記錄分離為獨(dú)立存儲過程,只在系統(tǒng)加載時(shí)統(tǒng)計(jì)1次,然后把統(tǒng)計(jì)結(jié)果以參數(shù)的方式傳遞給Row_number()二分法的存儲過程,這樣將大大提高分頁的效率。根據(jù)Row_number()函數(shù)的分頁原理,建立Row_number()二分法分頁并不難,其通用存儲過程為(@sum為獨(dú)立存儲過程統(tǒng)計(jì)的返回結(jié)果):Declare @orderStr varchar(244),if @pageSize*@pageIndex>@sum/2 @orderStr=order by @IDField desc ,else @orderStr=order by @IDField asc,select* from (select*, Row_Number() over(@orderStr) asRowNumber,From @TableName ) asTempTable where RowNumber between (@ PageIndex - 1) * @ PageSize + 1 and @PageIndex* @ PageSize. 2.2優(yōu)化 對于上文提到的Row_number()二分法分頁方案,在系統(tǒng)中還需要數(shù)據(jù)庫的合理設(shè)計(jì)和sql語句的優(yōu)化。對于上百萬的數(shù)據(jù)查詢,要提高查詢的效率,就要用到數(shù)據(jù)庫中的索引【7】,合理應(yīng)用索引會讓查詢速度達(dá)到成倍的提高。索引分為聚集索引和非聚集索引兩種類型,聚集索引在大數(shù)據(jù)量的查詢中,查詢的速度快于非聚集索引。所以,在大數(shù)據(jù)量的分頁時(shí),應(yīng)采用聚集索引。由于聚集索引在一個(gè)數(shù)據(jù)表里只有一個(gè),這個(gè)聚集索引的資源也就顯得格外的寶貴,主鍵的默認(rèn)設(shè)置為聚集索引,而很多時(shí)候查詢的條件,排序的條件并不是主鍵字段,所以應(yīng)該修改主鍵字段的設(shè)置,把它設(shè)置為非聚集的索引。 例如:以人員信息表mess(id,name,phone,number,work,hometown,email,time)做測試,id列為主鍵,設(shè)置為非聚集的類型,time為排序列,設(shè)置為聚集索引,這樣在做人員信息的查詢時(shí),就會按照時(shí)間的索引,快速的找到查詢的信息。一般對于多條件查詢,可以把多個(gè)查詢的條件集合在一起設(shè)置成為一個(gè)聚集索引。以上是僅對于一個(gè)數(shù)據(jù)表查詢時(shí)建立索引的原則。當(dāng)涉及到多個(gè)數(shù)據(jù)表時(shí),可按如下案例建立索引:mess(id,name,phone,number,work,hometown,email,time),user(userid,password,power)其中mess為人員信息表,user為密碼權(quán)限表。現(xiàn)在要查詢?nèi)藛T的信息和權(quán)限,需要兩表連接查詢。查詢語句為:select * from mess,user,where user.userid=mess.id order by time。根據(jù)這個(gè)查詢語句,為了提高兩表的連接效率,應(yīng)把userid字段和id字段先建立外鍵關(guān)系。根據(jù)返回的結(jié)果的需要,按照時(shí)間排序,對于mess表,依舊以id列為主鍵,time列結(jié)合id列為聚集索引,對于user表,因?yàn)槠ヅ涞臈l件為useid,要獲得人員的權(quán)限,應(yīng)該以userid為聚集索引查詢power列,這樣兩個(gè)表都建立了屬于各種的索引,能夠快速的查詢到相關(guān)信息,從而達(dá)到整體的查詢效率提高的目的。對于多表匹配時(shí),在相應(yīng)的單表里建立合理的索引能使查詢速率達(dá)到事半功倍的效果。 同數(shù)據(jù)庫的設(shè)計(jì)一樣,sql語句的優(yōu)化一樣有助于提高分頁的效率。通過測試比較,一個(gè)查詢條件直接用等號匹配的速度高于用 like+%的匹配速度。例如要在前臺根據(jù)條件查詢信息表中人員的姓名,工作和籍貫,若是用一句sql語句可以寫成:Select * from mess Where name like @name+’%’ and work like +@work+’%’ and home like @home+’%’。但是試想一下,擁有百萬的數(shù)據(jù)一次一次的像上述sql語句那樣like匹配,這樣會因?yàn)榇罅康钠ヅ湎膶氋F的時(shí)間。所以,存儲過程中的sql語句,最好分情況而定:通過查詢條件的不同動(dòng)態(tài)匹配sql語句,例如:If(name.text!=””) {sql=select * from messWhere name = @name},If(name.text==””&&work.text!=””&&status.text!==””) {sql=select * from messWhere status = @status and work = @work}。對于多表涉及到的多條件查詢,應(yīng)該把查詢范圍小的寫在查詢條件的前面,這樣可以縮小篩選的范圍,減少后面條件匹配的范圍,從而降低查詢的所用時(shí)間。如select * from mess,user,where user.userid=mess.id and user.name=’a’ order by time,這樣的sql語句應(yīng)該優(yōu)化改下為select * from mess,user,where user.name=’a’ and user.userid=mess.id order by time.同理,對于多表之間的匹配,也遵循匹配結(jié)果范圍小的兩個(gè)數(shù)據(jù)表優(yōu)先匹配。 3、性能實(shí)驗(yàn)分析 3.1測試平臺 數(shù)據(jù)庫:sql sever2008 數(shù)據(jù)表:人員信息表mess(bid,name,phone,number,work,hometown,email,time)物理大小:103MB,共有一百萬零三條數(shù)據(jù)記錄。中鐵建企業(yè)管理生產(chǎn)計(jì)劃統(tǒng)計(jì)系統(tǒng)中的項(xiàng)目表和施工單位表,項(xiàng)目表的物理大小在數(shù)據(jù)量為100萬條時(shí)為375.25MB,施工單位表共包括998個(gè)各級施工單位,物理大小為0.07MB。 查詢要求: 1.查詢mess表中的所有記錄,每頁返回十條記錄結(jié)果。 2.查詢中鐵建企業(yè)管理生產(chǎn)計(jì)劃統(tǒng)計(jì)系統(tǒng)中的項(xiàng)目表和施工單位表,返回項(xiàng)目的編號,項(xiàng)目的施工單位編號,施工單位的名稱,項(xiàng)目的名稱,項(xiàng)目的類型,項(xiàng)目的合同額,項(xiàng)目的開累數(shù),項(xiàng)目的剩余開累數(shù),及錄入員,每頁返回十條記錄結(jié)果。 測試環(huán)境:華碩筆記本電腦K43T,CPU:A6-3400M,內(nèi)存:2G。 操作系統(tǒng):win7旗艦版 3.2測試結(jié)果 根據(jù)查詢要求1記錄各分頁方案的所用時(shí)間: 表1數(shù)據(jù)表mess共有100萬條數(shù)據(jù) ms
根據(jù)查詢要求2記錄各分頁方案的所用時(shí)間(其中select top and NotIn和select top and max分頁方案因?yàn)榫窒扌圆荒軐Σ樵償?shù)據(jù)分頁): 表2項(xiàng)目表和施工單位表共有210萬條數(shù)據(jù) ms
通過表1,表2的數(shù)據(jù),可以發(fā)現(xiàn)Row_number()二分法是上述所有分頁研究方案中效果最好的分頁方案,由于Row_number()函數(shù)本身并不依賴數(shù)據(jù)表中的數(shù)字段,所以它可以在實(shí)際項(xiàng)目中廣泛的應(yīng)用,真正的提高了大數(shù)據(jù)的分頁效率。特別聲明:由于筆者所用的測試電腦本身的硬件低端,CPU處理速度慢,遠(yuǎn)不及真正的服務(wù)器的處理速度,所以,在真正的服務(wù)器上即使是千萬頁的信息讀取也是高效迅速的。 4、結(jié)束語動(dòng)態(tài)網(wǎng)頁設(shè)計(jì)中分頁顯示數(shù)據(jù)有多種實(shí)現(xiàn)方法,本文通過上述七種分頁方案的實(shí)驗(yàn)測試,比較各種分頁方案的優(yōu)缺點(diǎn),一步一步的分析推導(dǎo),提出了最優(yōu)的分頁方案Row_number()二分法,通過實(shí)際項(xiàng)目的測試,利用該方案能夠充分提高大數(shù)據(jù)分頁的效率,此方案對解決中大型系統(tǒng)的數(shù)據(jù)分頁具有一定的指導(dǎo)意義。 參考文獻(xiàn): [1] 洪新建,張陽,洪新華.對Web數(shù)據(jù)查詢分頁顯示的設(shè)計(jì)與實(shí)現(xiàn)[J]. 電腦開發(fā)與應(yīng)用, 2007, 6(6): 44. [2] 付文平,羅鍵.基于Web的分頁技術(shù)的設(shè)計(jì)與實(shí)現(xiàn)[J]. 計(jì)算機(jī)時(shí)代, 2007(10): 55. [3]張素智,劉中鋒.基于ASP. NET的Web數(shù)據(jù)分頁實(shí)現(xiàn)與性能優(yōu)化[J].鄭州輕工業(yè)學(xué)院學(xué)報(bào)(自然科學(xué)版),2010( 06) . [4]陳南. ASP. NET 中大數(shù)據(jù)量分頁技術(shù)的研究與實(shí)現(xiàn)[J].計(jì)算機(jī)應(yīng)用與軟件,2011( 04) . [5] 陳煥通,陳堯妃.基于存儲過程的數(shù)據(jù)快速分頁方法[J].軟件導(dǎo)報(bào),2008( 12) . [6]胡配祥,張成叔,陳良敏.SQL臨時(shí)表在科研管理系統(tǒng)數(shù)據(jù)處理中的應(yīng)用[J].洛陽理工學(xué)院學(xué)報(bào) (自然科學(xué)版),2011( 06) . [7] 陳偉柱,蘇中,張俐,王睿. 索引和查找方法 [P]. 中國專利:CN1979469,2007-06-13.
文章出處:http://www.cnblogs.com/wlandwl/p/paginaction.html 該文章在 2024/6/6 10:28:49 編輯過 |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |