[php/mysql/smarty] Dit kan toch beter, met minder queries?
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
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");
?>
$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
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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}
<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 -
Code (php)
1
2
3
4
5
6
7
8
9
10
11
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");
?>
$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.
@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.
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.
@Aar,
Mogelijkheid 1 met een stored view en uservars:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
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;
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
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 :)
Die view lijkt me het meest interessante...
Ik ga vanavond eens deze queries uitvoeren en wat ermee uittesten.
Ik ben persoonlijk ook van mening dat smarty met bepaalde dingen ook beter kan.
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?
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 ;)
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 -
@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....
Gewijzigd op 04/09/2012 20:17:23 door Ger van Steenderen