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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

java 倒序分页_翻动100万级的数据(自定义的MSSQL分页查询过程)

發(fā)布時(shí)間:2023/12/19 数据库 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 倒序分页_翻动100万级的数据(自定义的MSSQL分页查询过程) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

翻動(dòng)

100

萬(wàn)級(jí)的數(shù)據(jù)?——?只需幾十毫秒?之揭秘篇:有詳細(xì)的說明,不要錯(cuò)過。

感謝大家的支持!!!

昨天發(fā)了一個(gè)邀請(qǐng),邀請(qǐng)大家?guī)兔y(cè)試,效果還可以,下面小結(jié)一下:

通過內(nèi)部的計(jì)數(shù)器得知:訪問次數(shù)是

1071

(其中有好多是自己點(diǎn)的:)),人數(shù)不是太理想,本來是想看看上萬(wàn)人同時(shí)訪問的情況:)

系統(tǒng)資源的占用情況

內(nèi)存?——?很理想。

SQL

占用的內(nèi)存最大也沒有超過

65

M,一般是在

35

M左右;asp.net占用的內(nèi)存最大也沒有超過

40

M,一般是在

25

M左右。

CPU:

8

%左右,由于訪問次數(shù)不多,也不夠集中,所以這個(gè)數(shù)值也說明不了什么。自己連續(xù)點(diǎn)了n次下一頁(yè),發(fā)現(xiàn)CPU的使用率飄高,達(dá)到了

50

%左右。

但是對(duì)于

100

萬(wàn)的記錄,AMD?XP2000+?的CPU?幾十毫秒的放映速度,因該是可以接受的,甚至是很理想的吧。

畢竟服務(wù)器的CPU要比我的快很多吧,而且記錄也很難達(dá)到

100

萬(wàn)吧。

結(jié)果還是很滿意的,但是美中不足的是,我想看一下海量訪問的情況下的效果,

希望大家再支持一下,多點(diǎn)幾下,謝謝了。呵呵

另外說明一下:前n頁(yè)可以在

60

毫秒內(nèi)完成,n應(yīng)該是大于

500

的,小于多少嘛還沒有測(cè)試。后n頁(yè)就比較慢了,需要

500

毫秒左右。

下面討論一下翻頁(yè)的技巧吧。

我沒有用游標(biāo)、臨時(shí)表、

not?in

in

這些方法,并不是說他們的效率不高,而是我還沒有測(cè)試過。我只用了?top?,查了兩次表。

大家也可提供一些其他的方法,我來測(cè)試一下,看看在

100

萬(wàn)條的情況下的效果。(請(qǐng)不要給在存儲(chǔ)過程里面組串的,看著實(shí)在是太費(fèi)勁了)

討論的前提是在海量數(shù)據(jù)的情況下,至少是在

10

萬(wàn)以上的。如果是很少的數(shù)據(jù)呢,那怎么翻都可以了。也差不了多少。

1.

設(shè)置合理的索引

首先要做的是設(shè)置合理的索引,這個(gè)好像經(jīng)常被忽略,至少很少被談起。

注意:主鍵是索引的一種,而且是最快的一種。如果你都是把主鍵當(dāng)作排序字段的話,那么你已經(jīng)利用了索引。

不設(shè)置合理的索引的話,會(huì)導(dǎo)致查詢速度非常的慢,甚至?xí)斐沙瑫r(shí)。

這方面你可以做一個(gè)實(shí)驗(yàn):找一個(gè)表,填進(jìn)去

10

萬(wàn)條記錄,假設(shè)有ID?、addedDate等字段,在查詢分析器里面執(zhí)行一下

select

top

10

*

from?table

應(yīng)該立刻就能出現(xiàn)結(jié)果。

然后再執(zhí)行

select

top

10

*

from?table?order?by

ID(這時(shí)ID字段是主鍵)

也是立刻就出現(xiàn)了結(jié)果。

然后再執(zhí)行

select

top

10

*

from?table?order?by

addedDate?(這時(shí)addedDate字段沒有索引)

你會(huì)發(fā)現(xiàn)速度很慢。

現(xiàn)在給addedDate?加一個(gè)非聚集索引,然后在執(zhí)行上面的查詢語(yǔ)句,速度也變得很快了。

可見索引神奇的效果!

這是翻動(dòng)百萬(wàn)級(jí)記錄最基本的設(shè)置,具體到我的那個(gè)論壇的翻頁(yè),我是設(shè)置了BoardID、?replyDate兩個(gè)字段作為聯(lián)合索引的。

因?yàn)槭且谕粋€(gè)討論組李翻頁(yè),而且是按replyDate排序的。

2.

只返回需要的記錄

對(duì)于海量數(shù)據(jù),都讀出來做緩存,那是不可想象的(記錄少的話,也要看利用率,一般都是很浪費(fèi)的)。

所以呢如果一頁(yè)顯示

20

條的話名那就只都讀出來

20

條,這樣就很省內(nèi)存和時(shí)間。

注意:雖然ADO.NET里面有這個(gè)方法

SqlDataAdapter.Fill(DataSet1,startRecord,maxRecords,srcTable);

但是他還是要先從

SQL

里面把查詢語(yǔ)句的查出來的所有記錄都出來,然后在截取指定的記錄數(shù)。這對(duì)于

SQL

來說是一樣的,對(duì)于海量數(shù)據(jù)依然會(huì)很慢。

論壇里的首頁(yè)用的是

select

top

20

*

from?table?where

boardID?=

5

order?by

replyDate

desc

這樣呢就只返回了

20

條記錄,再加上索引的功勞,速度是非常快的。

3.

盡量減少字段的長(zhǎng)度

一個(gè)表可以建很多的字段,但是字段的總長(zhǎng)度不能超過

8060

B,也就是說如果你建了一個(gè)

char

(

8060

)的字段,就不能在建其他的字段了。

我在第一次的測(cè)試中(星期天的),把主題的所有信息都放在了一個(gè)表里面,包括了一個(gè)nvarchar(

3600

)的主題內(nèi)容的字段,復(fù)制記錄的時(shí)候發(fā)現(xiàn)非常的慢,

當(dāng)達(dá)到

9

萬(wàn)的時(shí)候,就已經(jīng)很慢的,勉強(qiáng)把記錄數(shù)拷貝到了

35

萬(wàn),加了索引,測(cè)試了一下,翻頁(yè)速度還是可以的,前n也都是很快的,后n頁(yè)就很慢了,

如果再加上查詢那就非常之慢了。

查看了一下數(shù)據(jù)文件嚇了一跳?——?他居然占用了

1.4

G的硬盤空間,怪不得拷貝和查詢都慢的要死呢。

于是修改了一下表結(jié)構(gòu),把那個(gè)nvarchar(

3600

)的主題內(nèi)容的字段踢了出去,放在一個(gè)單獨(dú)的表里面。

再重新拷貝記錄就非常的快了,很快就把記錄數(shù)從

16

表成了

1048577

。昨天的測(cè)試就是在這個(gè)條件下進(jìn)行的。

4.

技巧

終于到了翻頁(yè)算法的地方了,呵呵沒有等急吧。

思路呢就是先找到一個(gè)標(biāo)志,然后呢把大于(或小于)這個(gè)標(biāo)志的前n條記錄取出來。

什么?沒看懂。沒關(guān)系,我舉個(gè)例子吧。

假設(shè)是按ID倒序的,每一頁(yè)顯示

10

條記錄,有

100

條記錄,記錄號(hào)正好是

1

100

(怎么這么巧??為了說明方便嘛)

那么第一頁(yè)的記錄就是

100

91

、第二頁(yè)的記錄就是

90

81

、第三頁(yè)的記錄就是

80

71......

我現(xiàn)在要翻到第三頁(yè),那么要找到第

21

行的記錄的ID的值(也就是

80

),然后把小于等于

80

的記錄用top

10

取出來就行了。

查詢語(yǔ)句

declare

@pageSize

int

--返回一頁(yè)的記錄數(shù)

declare

@CurPage

int

--頁(yè)號(hào)(第幾頁(yè))1:第一頁(yè);2:第二頁(yè);......;-1最后一頁(yè)。

declare

@Count

int

declare

@id

int

set

@pageSize=

10

set

@CurPage?=

1

if

@CurPage?=?-

1

begin

--最后一頁(yè)

set

rowcount?@pageSize

select

@id=ID

from?table?order?by

ID

end

--定位

if

@CurPage?>

0

begin

set

@Count?=?@pageSize?*?(@CurPage?-

1

)?+

1

set

rowcount?@Count

select

@id=ID

from?table?order?by

ID

desc

end

--返回記錄

set

rowcount?@pageSize

select

*

from?table?where

ID?<=@id

order?by

ID

desc

set

rowcount

0

其中“定位”用了

select

@id=ID

from?table?order?by

ID

desc

這種方法,感覺上是很省內(nèi)存的,因?yàn)橹挥涗浟艘粋€(gè)ID,

然后用

select

*

from?table?where

ID?<=@id

order?by

ID

desc

取得最終需要的記錄

set

rowcount?@pageSize?相當(dāng)于?top?@pageSize?。

優(yōu)點(diǎn):無論翻到哪一頁(yè),內(nèi)存的占用情況都不變,多人訪問內(nèi)存也不會(huì)不變,很多人呢,還沒有測(cè)試出來:)

缺點(diǎn):單表、單排序字段。

http://community.csdn.net/Expert/TopicView3.asp?id=

4182510

發(fā)了這個(gè)帖子,回復(fù)的人很多,感謝大家的支持。這里有個(gè)誤會(huì)我不得不說明一下,免的誤人子弟。

在帖子里我并不是寫了個(gè)算法就完事了,而是說了很多翻動(dòng)海量數(shù)據(jù)要注意的地方,

比如建立合理的索引,只返回需要的記錄?,盡量減少字段的長(zhǎng)度?等注意到或沒有注意到的地方。

最后說的才是算法,可能是我的表達(dá)能力太差了吧,舉的例子給大家?guī)砹苏`會(huì)。

翻頁(yè)的語(yǔ)句?(?@pageSize?*?(@CurPage?-

1

)?+

1

)

--定位

declare

@id

int

select

top

41

@id=ID

from?table?order?by

ID

desc

--顯示數(shù)據(jù)

select

top

20

*

from?table?where

ID?<=@id

order?by

ID

desc

按照ID倒序排列(也就是按照

int

類型的字段排序)

一頁(yè)顯示

20

條記錄,這是顯示第三頁(yè)的語(yǔ)句

@pageSize?*?(@CurPage?-

1

)?+

1

=

20

*(

3-1

)?+

1

=

41

正是因?yàn)镮D是不連續(xù)的所以才需要用第一個(gè)語(yǔ)句來定位,如果是連續(xù)的那還用第一條語(yǔ)句做什么呢?

舉各少量數(shù)據(jù)的例子:

假設(shè)有

10

條記錄,ID是:

1000

500

320

205

115

110

95

68

4

1

。這回不寫連續(xù)的了免的誤會(huì)

一頁(yè)顯示兩條記錄,現(xiàn)在要顯示第三頁(yè),那么第三頁(yè)的id就是

115

110

先看第一條語(yǔ)句

select

top

5

@id=ID

from?table?order?by

ID

desc

不知道大家有沒有看懂這句,這時(shí)print?@id?得到的結(jié)果是

115

再看第二條語(yǔ)句

select

top

2

*

from?table?where

ID?<=

115

order?by

ID

desc

這時(shí)的記錄集就是

115

110

,也就是我們所需要的記錄了。

注意:不需要連續(xù)的ID,也不局限只能按ID排序,你可以換成ReplyDate(最后回復(fù)時(shí)間)字段,

當(dāng)然了

declare

@id

int

要改成

declare

@id?datetime

這里的ID?是主鍵,唯一標(biāo)識(shí)記錄的字段,它本身就是一種索引,而且是效率最高的索引。

A.唯一標(biāo)識(shí)記錄的字段的值怎么能隨意改動(dòng)呢,那不亂套了嗎?

B.主鍵是最快的索引,可能你還沒有意識(shí)到(一開始我就不知道,學(xué)了

SQL

很久以后才知道的),如果你的算法用它作為排序字段,那么速度會(huì)很快,會(huì)比用其他字段(沒有索引的字段)排序快很多。

C.用ReplyDate(最后回復(fù)時(shí)間)來排序,那么就必須給他建立索引(在海量數(shù)據(jù)的情況下),否則會(huì)超時(shí)的。

D.建立索引后,再執(zhí)行添加、修改、刪除會(huì)對(duì)數(shù)據(jù)庫(kù)帶來災(zāi)難性的折磨??

一開始我也是這么認(rèn)為的,但是為了能夠翻頁(yè),不得不加索引。

但是接下來的事實(shí)確打消了我的顧慮

先來看添加。

100

萬(wàn)條記錄是怎么弄出來的?大家可以看到帖子里有很多標(biāo)題一樣的主題,對(duì)了是復(fù)制出來的。

我先加了

16

條記錄,然后加上了索引。注意在

insert?into

之前就已經(jīng)建立好了索引!

接下來就是

insert?into?table

(...)

select

...

from?table

影響的行數(shù):

16

32

64

128

256

512

1024

2048

4096

8192

16384

32768

65536

131072

262144

524288

很快記錄就達(dá)到了

100

完了。

最后一次也只不過一兩分鐘(具體的時(shí)間忘記了,反正是很快了)。

同時(shí),論壇也提供了發(fā)貼的功能,只是在批量添加記錄的時(shí)候,把一些記錄的最后回復(fù)時(shí)間弄成了

2006

年,

所以,你發(fā)的帖子不會(huì)顯示在第一頁(yè)。但是你可以看到,執(zhí)行時(shí)間是很快的。

可見添加的時(shí)候是不成問題的,索引是倒序排列的,所以影響的行數(shù)絕對(duì)沒有你想象的那么多。

再來看修改。

看了sp1234的回復(fù),加了修改的功能,只是為了測(cè)試,所以呢可以修改標(biāo)題、最后發(fā)表時(shí)間、分組ID。

為什么可以修改這幾個(gè)字段呢?標(biāo)題是普通字段,最后發(fā)表時(shí)間和分組ID是索引字段。

修改這幾個(gè)字段需要的時(shí)間都是很快的,在最后回復(fù)時(shí)間的右面有?[改]?[刪]?字樣,大家可以試一試。

同樣,修改的時(shí)候,影響的行數(shù)也不是很多。

最后看刪除

不多說了,論壇提供了這個(gè)功能,試一下就知道了。另外,刪除的時(shí)候,不用重新建立一遍索引吧?

在來說一下使用范圍吧。

首先呢這只是一種方法,而不是一個(gè)通用的存儲(chǔ)過程,也就是說要根據(jù)情況作適當(dāng)?shù)男薷摹?/p>

最佳使用環(huán)境:

單表,單排序字段,可以利用索引。

注意事項(xiàng):

排序字段不必連續(xù),最好使用

int

、datetime類型的字段,字符串型的字段沒有試過,效果可能會(huì)略差。

表可以沒有主鍵,但是對(duì)于海量數(shù)據(jù)的情況下,必須建立合理的索引。

有一個(gè)比較致命的限制,大家好像都沒有發(fā)現(xiàn),那就是排序字段的重復(fù)性,

最好是沒有重復(fù)的,但不是說絕對(duì)不能有重復(fù)的記錄,有不要緊,只要不跨頁(yè)就行,跨頁(yè)的話就會(huì)擠掉若干條記錄,

用時(shí)間字段來排序,發(fā)生重復(fù)的記錄的可能性就很小了。

擴(kuò)展性:

bingbingcha(不思不歸,不孟不E,原來是頭大灰狼)?的回復(fù)很精彩

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

這樣的技巧在

SQL

區(qū)都討論過了..速度是很快的..但是滿足不了需求的..實(shí)用性太差了..現(xiàn)在的企業(yè)需要用到分頁(yè)的大部分都是多表查詢..單表分頁(yè)滿足不了需求的..

這個(gè)存儲(chǔ)過程可以擴(kuò)展..用臨時(shí)表+樓主的方法..是個(gè)不錯(cuò)的選擇..

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

對(duì)于多表關(guān)聯(lián)查詢,有兩種方法,第一種就是bingbingcha說的?——?“用臨時(shí)表+樓主的方法”,這是在海量數(shù)據(jù)的時(shí)候唯一可行的方法。

但是在小數(shù)據(jù)量的時(shí)候,這么些就有一點(diǎn)繁瑣,而且不容易歸納到通用的寫法里。

先來看一下查詢語(yǔ)句據(jù)的寫法:

聯(lián)合的

SELECT

a.ReplyID,?a.TopicID

FROM

dbo.BBS_Reply?a

INNER?JOIN

dbo.BBS_body?b

ON

a.BodyID?=?b.bodyID

where

a.ReplyID?>

10

單表的

SELECT

ReplyID,?TopicID

FROM

dbo.BBS_Reply

where

ReplyID?>

10

有沒有看到相同的地方:

select

顯示的字段

from

where

條件

那么單表查詢和多表查詢有什么區(qū)別呢?

至少有很多的多表(單字段排序)查詢都是可用這種方式的。

注意:我并沒有說所有的多表(單字段排序)查詢都可以用,看具體情況了。

這是一個(gè)效率最高(需要合理的索引的幫忙),比較通用的翻頁(yè)方法。不知道這次我有沒有講明白。

==============================================================================

CREATE?PROCEDURE

CN5135_SP_Pagination

/*

***************************************************************

**?千萬(wàn)數(shù)量級(jí)分頁(yè)存儲(chǔ)過程?**

***************************************************************

參數(shù)說明:

1.Tables?:表名稱,視圖

2.PrimaryKey?:主關(guān)鍵字

3.Sort?:排序語(yǔ)句,不帶Order?By?比如:NewsID?Desc,OrderRows?Asc

4.CurrentPage?:當(dāng)前頁(yè)碼

5.PageSize?:分頁(yè)尺寸

6.Filter?:過濾語(yǔ)句,不帶Where

7.Group?:Group語(yǔ)句,不帶Group?By

效果演示:http://www.cn5135.com/_App/Enterprise/QueryResult.aspx

***************************************************************/

(

@Tables

varchar

(

1000

),

@PrimaryKey

varchar

(

100

),

@Sort

varchar

(

200

)?=

NULL

,

@CurrentPage

int

=

1

,

@PageSize

int

=

10

,

@Fields

varchar

(

1000

)?=

'*'

,

@Filter

varchar

(

1000

)?=

NULL

,

@

Group?varchar

(

1000

)?=

NULL

)

AS

/*默認(rèn)排序*/

IF

@Sort

IS?NULL?OR

@Sort?=

''

SET

@Sort?=?@PrimaryKey

DECLARE

@SortTable

varchar

(

100

)

DECLARE

@SortName

varchar

(

100

)

DECLARE

@strSortColumn

varchar

(

200

)

DECLARE

@operator

char

(

2

)

DECLARE

@type

varchar

(

100

)

DECLARE

@prec

int

/*設(shè)定排序語(yǔ)句.*/

IF

CHARINDEX(

'DESC'

,@Sort)>

0

BEGIN

SET

@strSortColumn?=?REPLACE(@Sort,

'DESC'

,

''

)

SET

@operator?=

'<='

END

ELSE

BEGIN

IF

CHARINDEX(

'ASC'

,?@Sort)?=

0

SET

@strSortColumn?=?REPLACE(@Sort,

'ASC'

,

''

)

SET

@operator?=

'>='

END

IF

CHARINDEX(

'.'

,?@strSortColumn)?>

0

BEGIN

SET

@SortTable?=?SUBSTRING(@strSortColumn,

0

,?CHARINDEX(

'.'

,@strSortColumn))

SET

@SortName?=?SUBSTRING(@strSortColumn,?CHARINDEX(

'.'

,@strSortColumn)?+

1

,?LEN(@strSortColumn))

END

ELSE

BEGIN

SET

@SortTable?=?@Tables

SET

@SortName?=?@strSortColumn

END

SELECT

@type=t.name,?@prec=c.prec

FROM

sysobjects?o

JOIN

syscolumns?c

on

o.id=c.id

JOIN

systypes?t

on

c.xusertype=t.xusertype

WHERE

o.name?=?@SortTable

AND

c.name?=?@SortName

IF

CHARINDEX(

'char'

,?@type)?>

0

SET

@type?=?@type?+

'('

+

CAST

(@prec

AS?varchar

)?+

')'

DECLARE

@strPageSize

varchar

(

50

)

DECLARE

@strStartRow

varchar

(

50

)

DECLARE

@strFilter

varchar

(

1000

)

DECLARE

@strSimpleFilter

varchar

(

1000

)

DECLARE

@strGroup

varchar

(

1000

)

/*默認(rèn)當(dāng)前頁(yè)*/

IF

@CurrentPage?<

1

SET

@CurrentPage?=

1

/*設(shè)置分頁(yè)參數(shù).*/

SET

@strPageSize?=

CAST

(@PageSize

AS?varchar

(

50

))

SET

@strStartRow?=

CAST

(((@CurrentPage?-

1

)*@PageSize?+

1

)

AS?varchar

(

50

))

/*篩選以及分組語(yǔ)句.*/

IF

@Filter

IS?NOT?NULL?AND

@Filter?!=

''

BEGIN

SET

@strFilter?=

'?WHERE?'

+?@Filter?+

'?'

SET

@strSimpleFilter?=

'?AND?'

+?@Filter?+

'?'

END

ELSE

BEGIN

SET

@strSimpleFilter?=

''

SET

@strFilter?=

''

END

IF

@

Group?IS?NOT?NULL?AND

@

Group

!=

''

SET

@strGroup?=

'?GROUP?BY?'

+?@

Group

+

'?'

ELSE

SET

@strGroup?=

''

/*執(zhí)行查詢語(yǔ)句*/

EXEC

(

'

DECLARE?@SortColumn?'

+?@type?+

'

SET?ROWCOUNT?'

+?@strStartRow?+

'

SELECT?@SortColumn='

+?@strSortColumn?+

'?FROM?'

+?@Tables?+?@strFilter?+

'?'

+?@strGroup?+

'?ORDER?BY?'

+?@Sort?+

'

SET?ROWCOUNT?'

+?@strPageSize?+

'

SELECT?'

+?@Fields?+

'?FROM?'

+?@Tables?+

'?WHERE?'

+?@strSortColumn?+?@operator?+

'?@SortColumn?'

+?@strSimpleFilter?+

'?'

+?@strGroup?+

'?ORDER?BY?'

+?@Sort?+

'

'

)

GO

總結(jié)

以上是生活随笔為你收集整理的java 倒序分页_翻动100万级的数据(自定义的MSSQL分页查询过程)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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