[php/mysql/smarty] Dit kan toch beter, met minder queries?

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

- Ariën  -
Beheerder

- Ariën -

04/09/2012 08:06:44
Quote Anchor link
Ik heb een prachtig script geschreven in PHP, gebruikmakend van MySQL en Smarty die alle categorieeën ophaalt. En toont, maar ik ben niet tevreden over de opbouw van dit script:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$data
= array();
    $result_cats = mysql_query("SELECT ID, title FROM news_categories");
    while($newscat = mysql_fetch_assoc($result_cats)) {
        $sql = "SELECT id, title, date_posted, auteur FROM news WHERE catID ='".$newscat['ID']."' AND active='1' ORDER BY date_posted DESC LIMIT 5";
        $result_items = mysql_query($sql);
        while($item = mysql_fetch_assoc($result_items)) {
            $data[$newscat['title']][] = $item;
        }
    }

    $tpl->assign("news_categories",$data);
    $tpl->display("news_archive_index.tpl");
?>

Noot: Voor het gemak om alles hier tot relevante code te beschouwen heb ik de foutafhandeling er even uitgestript Afbeelding

Het punt is dat voor elke categorie die uit de tabel 'news_categories' wordt opgevraagd, dat er een query wordt gedraaid om het juiste bijbehorende nieuws uit de table 'news' op te halen. Niet zo efficient, want wat nou als je 25 categorieën hebt... 25 queries....
Overkill dus...

Hoe zou dit beter kunnen?
Ik heb al eerder gekeken naar JOINS, maar het resultaat heb ik nog niet kunnen vinden, ook in de template moeten daarvoor enkele wijzigingen worden aangepast vrees ik..

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{foreach name=categorie item=contact key=naam from=$news_categories}
                            <h1>{$naam}</h1>
                            <table width="80%" class="TableList tablesorter">
                            <thead>
                                <tr>
                                    <th width="60%">Titel</th>
                                    <th width="10%">Auteur</th>
                                    <th width="30%">Datum</th>
                                </tr>
                            </thead>
                            {foreach key=key item=item from=$contact}
                            <tbody>
                                <tr>
                                    <td width="60%"><a href="/news/{$item.id}">{$item.title}</a></td>
                                    <td width="10%">{$item.auteur}</td>
                                    <td width="30%">{$item.date_posted|date_format:"%e %b %Y om %H:%M"}</td>
                                </tr>
                            </tbody>
                            {/foreach}
                        </table>
                        {/foreach}

Wie zou me een opstapje kunnen geven naar een betere methode om de categorieën en het nieuws op te halen met enkele queries?
Gewijzigd op 04/09/2012 08:09:55 door - Ariën -
 
PHP hulp

PHP hulp

26/04/2024 07:39:58
 
Remco nvt

Remco nvt

04/09/2012 09:18:32
Quote Anchor link
Uit me hoofd:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php
    $data
= array();
    $sql = "SELECT news.id, news.title, news.date_posted, news.auteur, news_categories.ID as newscat_id, news_categories.title as newscat_title FROM news
        INNER JOIN news_categories ON news.catID = news_categories.ID  WHERE news.active='1' ORDER BY news.date_posted DESC LIMIT 5"
;
    $result_items = mysql_query($sql);
    while($item = mysql_fetch_assoc($result_items)) {
        $data[$item['newscat_title']][] = $item;
    }
    
    $tpl->assign("news_categories",$data);
    $tpl->display("news_archive_index.tpl");
?>


Als je een inner join doet vanuit het news naar de categorieen dan krijg je netjes bij elk nieuws bericht je title en id van de categorie. Als je daarmee (zoals je al deed) een key value array maakt dan heb je wat je wou.
 
Ger van Steenderen
Tutorial mod

Ger van Steenderen

04/09/2012 10:00:28
Quote Anchor link
Remco, als de eerste categorie 5 of meer items heeft is die de enige die geselecteerd wordt.

@Aar,
Door de LIMIT op het aantal news items per categorie, kan je dit niet op de normale manier met een JOIN oplossen.
Ik heb er wel een oplossing met een eigen SQL functie voor maar die moet ik even opduikelen. Wordt vervolgd.
 
Remco nvt

Remco nvt

04/09/2012 10:11:55
Quote Anchor link
Mmh, heb je gelijk in Ger. Over het LIMIT gekeken.
Persoonlijk heb ik niet graag directe limits op zulke queries.

Liever de boel in een cache gooien en dan uit de grote array de gewenste artikelen halen.
 
Ger van Steenderen
Tutorial mod

Ger van Steenderen

04/09/2012 12:28:54
Quote Anchor link
Hmz, weer een 'kromme tenen' moment. Een hele bak met data uit de database halen, en dan in PHP gaan filteren om een beperkt aantal over te houden.

@Aar,
Mogelijkheid 1 met een stored view en uservars:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CREATE VIEW news_top5
AS      
    SELECT news.*
    FROM
        (SELECT
            @lim := IF(@newlim IS NOT NULL, @newlim, 5),
            @curid := -1
        ) AS v,
        news
    WHERE
        CASE
            WHEN @curid <> catID THEN @row := @lim ELSE 1 END > 0
    AND
        (@row := @row - 1) >= 0
    AND
        (@curid := catID) IS NOT NULL
    ORDER BY
        catID, date_posted DESC

En dan deze query:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT
    c.id AS cid,
    c.title AS ctitle,
    n.id,
    n.title,
    n.autor,
    n.date_posted
FROM
    news_categories AS n
LEFT JOIN
    news_top5 AS n
    ON
       c.id = n.catID;
Gewijzigd op 04/09/2012 14:03:58 door Ger van Steenderen
 
Remco nvt

Remco nvt

04/09/2012 12:52:53
Quote Anchor link
Quote:
Hmz, weer een 'kromme tenen' moment. Een hele bak met data uit de database halen, en dan in PHP gaan filteren om een beperkt aantal over te houden


Neem aan dat dit tegen mij was.
Ben het er niet mee eens dat een volle bak aan data uit een DB halen per definitie slecht is.
Ik haal ze graag op omdat ik het dan in de cache kan gooien en ik dus alles nog met die data kan doen wat ik wil.
Want ik heb liever dat PHP een shift doet bijvoorbeeld dan dat ik een connectie heb naar me DB. Gezien dat vaak sneller een bottleneck is dan je cache en http server.

Daarnaast is dit met nieuws iets wat niet veel zal veranderen. De nieuwsgroepen al helemaal niet en de berichten die je hebt kan je telkens toevoegen aan je cache i.p.v. alles eruit te halen.

Dus ja, graag alle data :)
 
- Ariën  -
Beheerder

- Ariën -

04/09/2012 13:43:27
Quote Anchor link
Dat probleem met die JOINS en de LIMIT was ik ook al achter gekomen.
Die view lijkt me het meest interessante...

Ik ga vanavond eens deze queries uitvoeren en wat ermee uittesten.
 

04/09/2012 16:20:01
Quote Anchor link
Hmm interessant. Ik werk tegenwoordig ook steeds vaker met smarty, en ik heb altijd het gevoel dat ik een vies stukje verwerking krijg wanneer ik net als jou zo'n bak met data ophaal.

Ik ben persoonlijk ook van mening dat smarty met bepaalde dingen ook beter kan.
 
Ger van Steenderen
Tutorial mod

Ger van Steenderen

04/09/2012 16:51:49
Quote Anchor link
@Aar, wellicht ten overvloede, maar die CREATE VIEW hoeft maar één keer :-).
Wel even de query testen voordat je er een view van maakt, ik kon het zo snel niet in mijn archief vinden dus deze heb ik van internet geplukt. Goochelen op MYSQL ROW_NUMBER.

@Remco
Waarom gebruik je dan überhaupt nog een database?
 
Remco nvt

Remco nvt

04/09/2012 19:15:12
Quote Anchor link
Gewoon, om te gebruiken waarvoor die bedoeld is. Data opslaan.
Alleen alle data die niet niet elke 10 min wordt aangepast kan best wel worden gecached. Tis toch zonde om een pagina met informatie telkens uit een DB te halen?

Maar dit wordt een andere discussie dan welke het topic voor is bedoeld ;)
 
- Ariën  -
Beheerder

- Ariën -

04/09/2012 19:19:41
Quote Anchor link
Cachen kan ook, maar zit wat meer techniek voor achter. Ik weet dat Smarty ook e.e.a kan cachen. Daar moet ik me even goed in verdiepen.

Maar goed, zoveel load kan het nu ook weer niet zijn om uit een vier categorieen (kan ooit meer worden) vijf nieuwste items op te halen.
Gewijzigd op 04/09/2012 19:20:47 door - Ariën -
 
Erwin H

Erwin H

04/09/2012 19:23:32
Quote Anchor link
Een andere optie is nog om het met een UNION te doen. Twee nadelen: je moet wel eerst alle nieuws categorieen ophalen (dus twee queries) en je krijgt een draak van een query als je het voor 25 categorieen wilt doen (maar dan wel weer dynamisch, dus je hoeft het niet helemaal zelf uit te tikken).

@Remco, maar dan gebruik je database niet meer waar doe voor bedoelt is, en al helemaal php niet. php is geen kei in het verwerken van grote hoeveelheden data in arrays. Daar wordt het erg traag van....
 
Ger van Steenderen
Tutorial mod

Ger van Steenderen

04/09/2012 19:50:11
Quote Anchor link
And somethimes I love mssql:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
SELECT ROW_NUMBER() OVER (PARTITION BY catID ORDER date_POSTED) AS row
....
Gewijzigd op 04/09/2012 20:17:23 door Ger van Steenderen
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.