Avatar billede loevstroem Nybegynder
15. august 2010 - 00:50 Der er 7 kommentarer og
2 løsninger

PHP Pagination performance

Hej Eksperter,

Jeg har en udfordring med performance og visning af nye blog posts. De pågældende posts kommer internt fra mit site, og samtidig er der posts der bliver hentet via RSS. (posts fra eksterne blogs).

For at vise posts korrekt henter jeg de interne posts fra min database, og de eksterne ved brug af SimplePie. De eksterne posts bliver cachet. Jeg samler dem alle i et array efter dato (eftersom formålet er altid at vise de nyeste).

Jeg ønsker at udvide min funktion med mulighed for paging (10 posts. pr side). Det burde umiddelbart være simpelt at lave et script der viser 10 rækker fra mit array, men dette forudsætter at jeg henter alle interne posts ud ved start, eftersom jeg ikke ved hvor mange eksterne posts der er? Dette bekymrer mig, såfremt der skulle være 900 posts i min database.

Jeg håber I forstår min problemstilling..

På forhånd tak


$internalPosts = array();
$feedUrls = array();

include_once 'simplepie.inc';

class Post {
    public $title;
    public $link;
    public $description;
    public $publishedAt;

    public function __construct($title, $link, $description, $publishedAt) {
        $this->title = $title;
        $this->link = $link;
        $this->description = $description;
        $this->publishedAt = $publishedAt;
    } 
}

$posts = array();

// Convert internal posts to generic post.
foreach($internalPosts as $item){
    $posts[] = new Post($item->title, $item->link, $item->description, $item->publishedAt);
}

// Retrieve feeds and add posts.
$feed = new SimplePie();

foreach($feedUrls as $url){
    $feed->set_feed_url($url);
    $feed->set_cache_location($_SERVER['DOCUMENT_ROOT'].'/cache');
    $feed->init();

    foreach ($feed->get_items() as $item) {
        $posts[] = new Post($item->get_title(), $item->get_link(), $item->get_description(), $item->get_date('U'));
    }
}

// Sort function.
function byPublicationTimestamp($itemA, $itemB){
    return ($itemB->publishedAt - $itemA->publishedAt);
}

usort($posts, 'byPublicationTimestamp');

foreach($posts as $post){
    echo "<p><a href='$post->link'>$post->title</a><br/>" . date('l, j F Y', $post->publishedAt) . " - $post->description</p>";
}
Avatar billede danco Nybegynder
15. august 2010 - 02:08 #1
Jeg er ikke sikker på jeg forstår dit spørgsmål. Men jeg hvis jeg har forstået det korrekt så handler det om du har et problem med at trække dine posts frem 10 ad gangen.
Hvis jeg sad med det problem ville jeg nok overveje følgende.

Ved 900 posts i din database ville det tage nogen tid at hente ud og indsætte i et array, derfor ville jeg nok foreslå dig at du eksempelvis henter 10 posts ad gangen i takt med brugeren skal bruge dem. Evt. ved at oprette et Wall objekt indholdende et array af posts for den aktuelle visning.
Avatar billede showsource Seniormester
15. august 2010 - 08:44 #2
Jeg ville lave en count(*) af posts i db,
$ialt = mysql_result(mysql_query("SELECT COUNT(*) FROM tabel"),0);

og derefter finde antal sider med
$antalsider = round($ialt/10);

Så ved du hvor mange sidevisninger du har at lege med.
Avatar billede loevstroem Nybegynder
15. august 2010 - 11:00 #3
@showsource - det er umiddelbart ikke så simpelt som det.

@danco - jeg prøver at formulere mig anderledes.

Jeg har 900 posts i min egen database (A). Disse skal blandes med eksterne posts hentet igennem RSS feed (B)

Grundet jeg ikke ved hvor mange posts der kommer fra B, kan jeg ikke blot lave en simpel LIMIT i min query når jeg henter A.

Jeg ønsker at opnå 10 resultater pr. side. dette burde være nemt, hvis jeg har alt mit indhold i mit array (alle 900 posts), men jeg mener blot dette ødelægger performance på længere sigt.

Jeg håber mit problem er blevet mere forståeligt :)
Avatar billede intenz Novice
15. august 2010 - 11:58 #4
Hvis det er for besværligt at følge showsource's løsning med dit rss feed, så hent alle 900 i et array, og indsæt dem i en database (en per række). Den database kan du så bruge som en cache, og opdatere indholdet af den hver xx minut (med cronjob eller lign.).
Så vil du kunne lave count(*) på den.

Alternativt kan du også hente dem allesammen ud i et array og tælle dem, og så bare gemme antallet i en database, som du opdaterer hvert xx minut.

Du bør ikke hente alle 900 ud i et array hver gang, hvis du kun skal bruge 10. Det vil hurtigt komme til at gå ud over performance.
Avatar billede coderdk Praktikant
15. august 2010 - 17:53 #5
Lav evt en SELECT med et LIMIT, efterfølgende kan du eksekvere SELECT FOUND_ROWS() for at få det totale antal :)
Se http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_found-rows
Avatar billede loevstroem Nybegynder
15. august 2010 - 21:34 #6
Hej med jer,

Jeg har lavet et cronjob der henter de eksterne posts (B) og gemmer dem i min database. Så kan jeg begrænse min data igennem min query.

Smid et svar og så kan i dele points :)
Avatar billede showsource Seniormester
15. august 2010 - 22:47 #7
Jeg springer over med point
Avatar billede intenz Novice
15. august 2010 - 23:17 #8
Mit kommer her :)
Avatar billede coderdk Praktikant
16. august 2010 - 09:29 #9
Hvis du kan bruge SELECT/LIMIT/FOUND_ROWS :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester