webForumDet fria alternativet

Paging - vilken metod är bäst?

ASP

10 svar · 631 visningar · startad av joup

Medlem sedan feb. 2002116 inlägg
Frågan#1

Hej,

Jag har en fråga om paging med ASP/VBScript och en MS SQL Server-databas. Vad jag vet finns det bara två olika sätt att fixa paging, och jag undrar helt enkelt vilket som är bäst.

1. Man använder paging-metoden i ASP. Exempel:

pagesize = request("sidstorlek")
pagenumber = request("sidnummer")

if pagesize = "" then
pagesize = 30
else
pagesize = request("sidstorlek")
end if

if pagenumber = "" then
pagenumber = 1 
else
pagenumber = request("sidnummer")
end if

pagenumber=Cint(pagenumber)
pagesize=Cint(pagesize)

SQL = "SELECT * from nyheter Order by id desc"

Set RS = Server.CreateObject("ADODB.Recordset")

RS.cursorlocation=aduseclient
RS.cachesize=5

RS.CursorType = 1
RS.PageSize = pagesize

RS.Open SQL, Connection

pagecount = RS.PageCount

RS.AbsolutePage = pagenumber

antal = 1
while antal <= pagesize and not RS.EOF

2. Man använder subqueries i SQL-satsen. Exempel:

SELECT TOP 39 spel.id, spel.live, spel.uppdaterad, spel.namn, spel.release_type, spel.release AS datum, spel.spelare, spel.genre FROM spel where id not in (select top " & visar & " id from spel where release>'" & now-5 & "' order by release, release_type, namn) AND release>'" & now-5 & "' ORDER BY release, release_type, namn

Nu till själva frågan. Om man har en väldigt belastad hemsida (många besökare), vilken av dessa två metoder är bäst när det kommer till att dela upp en diskussionsforum i flera olika sidor, rent prestandamässigt? Tänk att tabellen har ungefär 100.000-200.000 poster.

Som jag ser det verkar båda metoderna ha nackdelar som kan vara dåliga för prestandan. Alternativ 1 så hämtar man ju hela tabellen med SQL-kommandot (ingen begränsning med top-kommando) vilket inte kan vara bra. Alternativ 2 så använder man ju subqueries, som kanske inte är så bra heller?

Någon som har någon erfarenhet av dessa metoder, och vet vilken som är snabbast/effektivast för en stor tabell som dessutom är hårt belastad?

Medlem sedan maj 20012 812 inlägg
#2

Helt klart är det bästa att låta MS ta hand om din Paging. Din version är dock ett mycket dåligt exempel på hur man kan göra det. Ut på nätet och sök så hittar du bättre lösningar.

- magnus

Medlem sedan sep. 20026 425 inlägg
#3

GetRows() och paging :D

Medlem sedan maj 20012 812 inlägg
#4

Problemet med GetRows() i detta exempel, är att du skickar alla information från databasen till webservern och lägger detta i recordsetet.

Om du då har 1 miljon rader i databas, så blir det en del data som måste skickas för att visa 10 rader.

- magnus

Medlem sedan aug. 20002 272 inlägg
#5

Gladh skrev:

Problemet med GetRows() i detta exempel, är att du skickar alla information från databasen till webservern och lägger detta i recordsetet.

Om du då har 1 miljon rader i databas, så blir det en del data som måste skickas för att visa 10 rader.

- magnus

Det var intressant :)
Och hur ska man få till en bättre lösning?
Så att recordsetet endast innehåller de poster som man ska visa?

Medlem sedan maj 2001431 inlägg
#6

Byt till MySQL/Postgresql och använd LIMIT ;)

Medlem sedan maj 20012 812 inlägg
#7

Byt till MySQL/Postgresql och använd LIMIT

Eller Oracle och använd ROWNUM.

Vill du göra det i SQL Server så använd dig av en lösning med SP. Men som sagts innan, ut på google och sök på SQL Server, SP och Paging. Så kommer du hitta massor med lösningar, vissa bra och andra mindre bra.

- Magnus

Medlem sedan feb. 2002116 inlägg
#8

Hittade faktiskt en lösning igår när jag sökte runt lite på webben som jag implementerat på min hemsida, och som jag faktiskt tycker har fått upp prestandan en del (jag körde med alt. 2 tidigare).

Man använder sig av en Stored Procedure som ser ut så här:

CREATE PROCEDURE "ForumPaging"

@Page int,
@Size int,
@forumid int

AS

DECLARE @Start int, @End int

BEGIN TRANSACTION GetDataSet

SET @Start = (((@Page - 1) * @Size) + 1)
IF @@ERROR <> 0
	GOTO ErrorHandler

SET @End = (@Start + @Size - 1)
IF @@ERROR <> 0
	GOTO ErrorHandler

CREATE TABLE #TemporaryTable
(
	Row int IDENTITY(1,1) PRIMARY KEY,
	prio int,
	originalid int,
	kopia int,
	senastav varchar(25),
	typ int,
	id int,
	forumid int,
	amne varchar(100),
	av int,
	namn varchar(25),
	senaste datetime,
	AntSvar int,
	Sidor int,
	stangd int,
	meddelande varchar(200)
)
IF @@ERROR <> 0
	GOTO ErrorHandler

INSERT INTO #TemporaryTable
SELECT forum.prio, forum.originalid, forum.kopia, forum.senastav, forum.typ, forum.id, forum.forumid, forum.amne, forum.av, forum.namn, forum.senaste, COUNT(f2.id) AS AntSvar, COUNT(f2.id)/40 AS Sidor, forum.stangd, CAST(forum.meddelande as VARCHAR(200)) as meddelande FROM forum LEFT JOIN forum as f2 ON forum.id = f2.svarsid WHERE forum.original=1 and forum.forumid = @forumid GROUP BY forum.id, forum.prio, forum.originalid, forum.kopia, forum.senastav, forum.typ, forum.id, forum.forumid, forum.amne, forum.av, forum.namn, forum.senaste, forum.stangd, CAST(forum.meddelande AS VARCHAR(200)) ORDER BY forum.prio desc, forum.senaste desc
IF @@ERROR <> 0
	GOTO ErrorHandler

SELECT prio, originalid, kopia, senastav, typ, id, forumid, amne, av, namn, senaste, AntSvar, Sidor, stangd, meddelande
FROM #TemporaryTable
WHERE (Row >= @Start) AND (Row <= @End)
IF @@ERROR <> 0
	GOTO ErrorHandler

DROP TABLE #TemporaryTable

COMMIT TRANSACTION GetDataSet
RETURN 0

ErrorHandler:
ROLLBACK TRANSACTION GetDataSet
RETURN @@ERROR

Är detta en bra/bättre lösning? Eller finns det vassare ändå?

Bör även tillägga att byta databas till MySQL eller något annat inte är ett alternativ. Jag har precis bytt från MySQL (eftersom det buggade rätt friskt under Win 2003) till MSSQL, och jag tänker inte byta tillbaka. :)

Medlem sedan juni 20003 076 inlägg
#9

klicka på länken i mitt sista inlägg! :)
http://www.webforum.nu/showthread.php?s=&forumid=53&threadid=92823

Medlem sedan feb. 2002116 inlägg
#10

Förresten, hur skall man anropa en SP "bäst" i ASP?

Just nu kör jag bara med

SQL = "EXEC Paging @Page=" & sida & ", @Size=31, @forumid=" & forumid
Set RS = Connection.Execute(SQL)

Är detta bra, eller finns det bättre/snabbare sätt att anropa en SP?

Medlem sedan okt. 2002103 inlägg
#11

joup skrev:

Set RS = Connection.Execute(SQL)

Du får ganska osnabba inställningar när du gör så där...

dim rstPage
Set rstPage = Server.CreateObject("ADODB.Recordset")
With rstPage
  .CursorLocation = 3 ' adUseClient
  .Open "EXEC sp_name", myConnection,0,1
End With

Så där minskar du ned på databasens ansträngning. 0,1 är readonly, forwardonly eller nåt sånt, en s k firehose cursor blir det iaf. Den här koden är väldigt testad. En sak att tänka på är att om du har ett recordset öppet måste du skapa en ny connection för recordset nummer 2, eller i min kod öppna med connection-strängen där det står myConnection i stället för ett connection-objekt. Gör man inte det så blir det en server-cursor på #2 och då körs det sp_cursorfetch-procedurer i SQL servern som försämrar prestanda märkbart. I fall målet är att lätta upp för SQL Servern så är denna kod att rekommendera som sagt.

268 ms totalt · 4 externa anrop · v20260731065814-full.1dc6f849
123 ms — deklarationer (db)
0 ms — hämta statistik (cache)
141 ms — hämta tråd, inlägg och bilagor (db)
124 ms — ändringar (db)