webForumDet fria alternativet

Databasabstraktionslager med sidindelning

PHP

3 svar · 391 visningar · startad av Troxy

Medlem sedan mars 20041 505 inlägg
Frågan#1

Hejsan. Jag sitter i en jobbig situation just nu. :l

Nu vill jag helt enkelt skapa en sidindelning på en SQL-fråga med 10000+ rader. Jag vill visa 100 poster per sida med framåt/bakåt-länkar.
Problemet är att SQL-frågan kommer från SQL Server 2000, som är helt handikappad vad gäller sidindelning eftersom den saknar LIMIT och inte har någon motsvarande funktion.

Efter många timmars trixande med SQL-frågor så har jag kommit fram till att jag helt enkelt blir tvungen att lösa sidindelningen i programmeringen, dvs jag hämtar alla tusentals rader med SQL och fetchar dom jag vill visa med PHP. Men det rör sig trots allt om tusentals poster, vilket betyder att servern måste hämta alla rader igen och igen när man byter sida, vilket blir seeeegt. Det krävs väll istället någon sorts buffering?

Så nu undrar jag hur jag ska lösa detta?
Är det någon här i forumet som har en fungerande lösning för sidindelning i PHP mot SQL Server 2000?

Just nu så har jag testat lite med nya fräscha PDO för PHP5, men den verkar inte vara helt stabil än eftersom jag inte får cursors att fungera öht.
Vet någon om man kan fixa sidindelning med PDO?

Jag bygger en ganska komplex sida och vill helst att alla SQL-frågor ska köras mot ett databasabstraktionslager (ett fint ord).

Samtidigt så ligger chefen på och tjatar att allting måste bli klart, men det är ett problem som jag får lösa själv ;)

Medlem sedan apr. 200730 inlägg
#2

Jag är inte helt hundra (har inte SQL på denna burk) men jag tror om du kan kombinera variabel med TOP så borde du kunna fixa filtreringen i SQL.

Jag utgår i från att du skickar med vart du vill ha ifrån (index) och hur många per sida (vilket också blir stoppet.) Testa att labba med följande. Inte världens snyggaste men det kanske går.

declare @hitsperpage as int
declare @index as int

set @hitsperpage = 100
set @index = 500

select top @index * into #previous from tbl order by 1
select top @hitsperpage * from tbl where id not in (select id from #previous) order by 1
Medlem sedan mars 20041 505 inlägg
#3

trashhash, tack för ditt svar. Din princip är till viss del fungerande, men tyvärr så går den inte att använda om man exempelvis vill sortera efter datum.
Dessutom blir SQL-frågorna i många fall väldigt komplexa. Säg att man har en SQL-fråga vars resultat bygger på en JOIN från tre, fyra olika tabeller. Då måste man skriva sin JOIN två gånger, vilket gör att SQL-frågorna blir dubbelt så långa.

Nu verkar jag dock ha kommit på en hyffsad lösning som bygger på temporära tabeller, SELECT INTO-uttrycket och IDENTITY:
Man ställer sin SQL-fråga som hämtar själva resultatet man vill visa. Detta lagras i en temporär tabell.
Själva finessen är att man även använder IDENTITY som ger varje post ett unikt id i temp-tabellen:

SELECT IDENTITY(INT,1,1) AS id, t1.user, ....
INTO #temp
FROM tabell1 t1 INNER JOIN tabell2 t2 ON (t1.user = t2.user)
ORDER BY ...

Nu har alla poster i den temporära tabellen fått varsitt id.
Då kan man använda BETWEEN för att begränsa urvalet av poster:

SELECT * FROM #temp WHERE id BETWEEN 50 AND 100

Jag har testkört lite och det verkar fungera helt okej, inte supersnabbt men godkänt.
Prestantamässigt så är det knappast optimalt.
Men kodmässigt så är det smidigt eftersom man slipper skriva allting två gånger.

Medlem sedan apr. 200730 inlägg
#4

Haha att jag inte tänkte på between. Men jag tycker lösning verkar helt ok, om du vill prova optimera kan du prova med en subselect istället för temptabell men jag är tveksam om du tjänar så mycket på det. Så finns det alltid index om du inte har redan applicerat det.

250 ms totalt · 4 externa anrop · v20260731065814-full.86ec41c2
121 ms — deklarationer (db)
0 ms — hämta statistik (cache)
126 ms — hämta tråd, inlägg och bilagor (db)
119 ms — ändringar (db)