大数据量分页查询方法(转)
? ? ? 本文旨在介紹一種對(duì)數(shù)據(jù)庫中的大數(shù)據(jù)量表格進(jìn)行分頁查詢的實(shí)現(xiàn)方法,該方法對(duì)應(yīng)用服務(wù)器、數(shù)據(jù)庫服務(wù)器、查詢客戶端的cpu和內(nèi)存占用都較低,查詢速度較快,是一個(gè)較為理想的分頁查詢實(shí)現(xiàn)方案。?
1.問題的提出?
在軟件開發(fā)中,大數(shù)據(jù)量的查詢是一個(gè)常見的問題,經(jīng)常會(huì)遇到對(duì)大量數(shù)據(jù)進(jìn)行查詢的場(chǎng)景。
常見的對(duì)大數(shù)據(jù)量查詢的解決方案有以下兩種:
(1)、將全部數(shù)據(jù)先查詢到內(nèi)存中,然后在內(nèi)存中進(jìn)行分頁,這種方式對(duì)內(nèi)存占用較大,必須限制一次查詢的數(shù)據(jù)量。
(2)、采用存儲(chǔ)過程在數(shù)據(jù)庫中進(jìn)行分頁,這種方式對(duì)數(shù)據(jù)庫的依賴較大,不同的數(shù)據(jù)庫實(shí)現(xiàn)機(jī)制不通,并且查詢效率不夠理想。以上兩種方式對(duì)用戶來說都不夠友好。
?
2.解決思路?
通過在待查詢的數(shù)據(jù)庫表上增加一個(gè)用于查詢的自增長(zhǎng)字段,然后采用該字段進(jìn)行分頁查詢,可以很好地解決這個(gè)問題。下面舉例說明這種分頁查詢方案。?
(1)、在待查詢的表格上增加一個(gè)long型的自增長(zhǎng)列,取名為“queryId”,mssql、sybase直接支持自增長(zhǎng)字段,oracle可以用sequence和trigger來實(shí)現(xiàn)。然后在該列上加上一個(gè)索引。
添加queryId列的語句如下:?
Mssql: [QUERYID] [bigint] IDENTITY (1, 1)?
Sybase: QUERYID?? numeric(19)?? identity?
Oracle:?
CREATE SEQUENCE queryId_S?
????????? INCREMENT BY 1?
????????? START WITH 1?
???????????? MAXVALUE 999999999999999 MINVALUE 1?
???????????? CYCLE?
???????????? CACHE 20?
???????????? ORDER;?
CREATE OR REPLACE TRIGGER queryId_T BEFORE INSERT?
????????????? ON "test_table"?
????????????? FOR EACH ROW?
BEGIN?
?????? select queryId_S.nextval into :new.queryId from dual;?
END;?
(2)、在查詢第一頁時(shí),先按照大小順序的倒序查出所有的queryId,
語句如下:select queryId from test_table where + 查詢條件 +order by queryId desc 。
因?yàn)橹皇遣樵僸ueryId字段,即使表格中的數(shù)據(jù)量很大,該查詢也會(huì)很快得到結(jié)果。然后將得到的queryId保存在應(yīng)用服務(wù)器的一個(gè)數(shù)組中。?
(3)、用戶在客戶端進(jìn)行翻頁操作時(shí),客戶端將待查詢的頁號(hào)作為參數(shù)傳遞給應(yīng)用服務(wù)器,服務(wù)器通過頁號(hào)和queyId數(shù)組算出待查詢的queyId最大和最小值,然后進(jìn)行查詢。?
算出queyId最大和最小值的算法如下,其中page為待查詢的頁號(hào),pageSize為每頁的大小,queryIds為第二步生成的queryId數(shù)組:?
???????? int startRow = (page?-?1) * pageSize
??????? int endRow = page * pageSize?-?1;?
????????????? if (endRow >=queryIds.length)?
?????????? ???? {?
?????????? ???????? endRow = this.queryIds.length?-?1;?
???????????? ?? }?
???????? long startId =queryIds[startRow];?
???????? long endId =queryIds[endRow];?
查詢語句如下:?
String sql = "select * from test_table" + 查詢條件 + "(queryId <= " + startId + " and queryId >= " + endId + ")";?
3.效果評(píng)價(jià)?
該分頁查詢方法對(duì)所有數(shù)據(jù)庫都適用,對(duì)應(yīng)用服務(wù)器、數(shù)據(jù)庫服務(wù)器、查詢客戶端的cpu和內(nèi)存占用都較低,查詢速度較快,是一個(gè)較為理想的分頁查詢實(shí)現(xiàn)方案。經(jīng)過測(cè)試,查詢4百萬條數(shù)據(jù),可以在3分鐘內(nèi)顯示出首頁數(shù)據(jù),以后每一次翻頁操作基本在2秒以內(nèi)。內(nèi)存和cpu占用無明顯增長(zhǎng)。
?
補(bǔ)充:
不久前我也開發(fā)過這樣的一個(gè)數(shù)據(jù)庫,解決的辦法是: 1 硬件方面,提高內(nèi)存容量(這是最重要的),將更多的內(nèi)存給予ORACLE固定使用。 2 數(shù)據(jù)庫方面,拆分大型表單,使用分時(shí)間段數(shù)據(jù)庫,我單位有一個(gè)巨型數(shù)據(jù)也是采用了這種方法!(這非常重要,速度可以提高幾十倍左右)。 3 編程方面,盡量不要使用ODBC,采用ORACLE驅(qū)動(dòng)編程,用ODBC太慢。加入每日的統(tǒng)計(jì),加入到你的日?qǐng)?bào)表中去,月底可以加入每月的報(bào)表等。 4 看書,查看ORACLE的書籍,對(duì)這方面問題應(yīng)該會(huì)有很好的回答(看的書,應(yīng)該在700頁以上,以清華的書為佳)。
?
我認(rèn)為數(shù)據(jù)分區(qū)、分成多個(gè)表、增加內(nèi)存、換更好的機(jī)器都是物理上的,當(dāng)然她帶來的速度的改善是有的。但是性能的改善一般比較少做多10倍到100倍之間。 對(duì)Oracle我不熟悉,但在SQL Server中最有效和可行的辦法是優(yōu)化數(shù)據(jù)庫結(jié)構(gòu)和索引。 對(duì)于優(yōu)化數(shù)據(jù)庫有根據(jù)事務(wù)型和數(shù)據(jù)倉庫型分為兩個(gè)方面。 偏重事務(wù)需要插入、更新速度快,所以一般這樣的表索引比較少,字段數(shù)目也少 數(shù)據(jù)倉庫需要查詢速度快,他一般會(huì)根據(jù)查詢可能出現(xiàn)的條件建立所有的索引,形成所謂的索引覆蓋。在大數(shù)據(jù)量的數(shù)據(jù)庫中,一旦某個(gè)查詢不能完全利用索引,就會(huì)形成表掃描。這是最壞的情況,查詢速度同數(shù)據(jù)量成正比。而如果能完全利用索引,查詢速度只有在數(shù)據(jù)量變化幾個(gè)等級(jí)才會(huì)有一些變化。我曾經(jīng)測(cè)試過一個(gè)庫存表150條記錄,索引建立不好一個(gè)查詢需要4分鐘,對(duì)索引優(yōu)化以后1秒不到。如果數(shù)據(jù)單純作為查詢可以取消對(duì)該表的日志功能。 我一般是分成兩個(gè)庫,一個(gè)處理事務(wù),一個(gè)處理查詢,然后建立一個(gè)定期事務(wù)把事務(wù)數(shù)據(jù)增加到查詢庫中。 總的來說,只有才所有軟的手段不能解決問題的情況下才采用物理的方法。但是物理的方法也不是單純?cè)黾討?yīng)
轉(zhuǎn)載于:https://www.cnblogs.com/zhaolizhe/p/6945852.html
總結(jié)
以上是生活随笔為你收集整理的大数据量分页查询方法(转)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: #51CTO学院四周年# 还好没放弃,终
- 下一篇: window 效率神器:Wox