[PHP/MySQL] Beste performance voor dit stukje code

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • commeric
  • Registratie: November 2002
  • Laatst online: 14-08 22:32
Ik ben bezig met het ontwikkelen van een forum. Nu zit ik in het begin al met een 'probleem'; Met de onderstaande code worden de categorien en de bijbehorende foras opgehaald.
Het resultaat is bijv dit:
>>Harde waren<<
Processors, Mobo's & Geheugen
Passen er in de BP6 nou wel of geen Itaniums...
Die-Hard Overclocking & Cooling
Voor alle info over het op-, over-, onder- en doorklokken van je teergeliefde XT.

>> Devschuur® <<
Webdesign & Graphics
Het forum voor webdesign, (D)HTML, Javascript, graphics, 3D-rendering, Flash en alles wat ermee te maken heeft.
Programming & Webscripting
Het programmeer en webscripting forum bij uitstek voor echte applicaties, PHP, MySQL, ASP, etc.

Nu wil ik uitteraard een zo goed mogelijke preformance hebbenl; zosnel mogelijk met zo min mogelijk recources. Ik heb daarbij 2 verschillende manieren bedacht om dit resultaat te krijgen. Nu vraag ik me alleen af welke dus de beste preformance geeft. Het forum gaat intensief worden gebruikt (gemiddeld 100 users online).
Ik heb al met een timertje bijgehouden welke het snelste is, maar dat wil denk ik niet zeggen welke het 'beste' is als het script heel vaak wordt opgevraagd.
Methode 1: ~0,020 s
Methode 2: ~0,016 s

Korte uitleg:
Methode 1 Haalt met 1 query de categorien op en maakt per categorie een query om de forum info op te halen.
Methode 2 Haalt met 2 query's de categorien en de forums op en zet ze in arrays. Waarna er met 2 loops de arrays worden uitgelezen

De code
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//Method 1 - Useing for every category a query + 1 general query
$query = "  SELECT 
                c.id,
                c.title,
                c.order
            FROM
                category c
            ORDER BY
                c.order
        ";
$cat_result = mysql_query($query);

while ($cat_list = mysql_fetch_object($cat_result))
{
    echo 'Category : ' . $cat_list->title . '<BR>';
    $query = "  SELECT
                    f.*
                FROM
                    forum f
                WHERE
                    f.cat_id = '$cat_list->id'
                ORDER BY
                    f.order         
            ";
    $forum_result = mysql_query($query);

    while ($forum_list = mysql_fetch_object($forum_result))
    {
        echo '<B>' . $forum_list->title . '</B><BR>';
        echo '<I>' . $forum_list->description . '</I><BR>';     
    }
    echo '---<BR><BR>';
}


//Method 2 - Useing 2 querys to store info in array
$query = "  SELECT 
                c.id,
                c.title,
                c.order
            FROM
                category c
            ORDER BY
                c.order
        ";
$cat_result = mysql_query($query);

$i = 0;
while ($cat_list = mysql_fetch_object($cat_result))
{
    $arr_cat[$i]['id'] = $cat_list->id;
    $arr_cat[$i]['title'] = $cat_list->title;
    $arr_cat[$i]['order'] = $cat_list->order;
    $i++;
}


$query = "  SELECT
                    f.*
                FROM
                    forum f             
                ORDER BY
                    f.cat_id,
                    f.order
                    
                
            ";
$forum_result = mysql_query($query);

$i = 0;
while ($forum_list = mysql_fetch_object($forum_result))
{       
    $arr_forum[$i]['id'] = $forum_list->id;
    $arr_forum[$i]['catid'] = $forum_list->cat_id;
    $arr_forum[$i]['title'] = $forum_list->title;
    $arr_forum[$i]['order'] = $forum_list->order;
    $arr_forum[$i]['description'] = $forum_list->description;
    $i++;   
}

for ($i=0;$i<count($arr_cat);$i++)
{
    echo '<B><u> >> Category : ' . $arr_cat[$i]['title'] . ' << </B></U><BR>';
    
    for ($b=0;$b<count($arr_forum);$b++)
    {
        if ($arr_forum[$b]['catid']==$arr_cat[$i]['id'])
        {
            echo '<B>' . $arr_forum[$b]['title'] . '</B><BR>';
            echo '<I>' . $arr_forum[$b]['description'] . '</I><BR>';            
        }       
    }
echo '---<BR><BR>';
}

[ Voor 15% gewijzigd door commeric op 26-12-2003 20:30 ]


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 16:32
Kan je het niet met 1 query doen?

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Spider.007
  • Registratie: December 2000
  • Niet online

Spider.007

* Tetragrammaton

offtopic:
het is performance
:)

[ Voor 102% gewijzigd door Spider.007 op 26-12-2003 23:39 ]

---
Prozium - The great nepenthe. Opiate of our masses. Glue of our great society. Salve and salvation, it has delivered us from pathos, from sorrow, the deepest chasms of melancholy and hate


Acties:
  • 0 Henk 'm!

  • djluc
  • Registratie: Oktober 2002
  • Laatst online: 16:51
Bij grote aantallen is de methode met 1 query veel sneller.

Acties:
  • 0 Henk 'm!

  • Tux
  • Registratie: Augustus 2001
  • Laatst online: 16-09 19:01

Tux

djluc schreef op 26 december 2003 @ 21:04:
Bij grote aantallen is de methode met 1 query veel sneller.
Die is er dus niet ;)

De eerste methode heeft een aantal queries van aantal categorieën * 2 en de tweede heeft 2 queries.

Er is misschien nog een methode met maar één query mogelijk maar hoe dat moet weet ik zelf ook niet :P

The NS has launched a new space transportation service, using German trains which were upgraded into spaceships.


Acties:
  • 0 Henk 'm!

  • djluc
  • Registratie: Oktober 2002
  • Laatst online: 16:51
Verbeteringen in snelheid: fetch_assoc() gebruiken.
SELECT * FROM forums LEFT JOIN categories als query om alles in 1 keer op te halen?

Het lijkt hier een beetje op: http://codewalkers.com/archives/sqlhelp/338.html

[ Voor 24% gewijzigd door djluc op 26-12-2003 21:17 ]


Acties:
  • 0 Henk 'm!

  • commeric
  • Registratie: November 2002
  • Laatst online: 14-08 22:32
Ik heb nog eens diep nagedacht en heb nu de volgende query bedacht.
Deze checkt gewoon elke keer of er al een nieuwe categrorie is en zoja dan wordt die categorie afgedrukt.
Deze methode werkt in 0,009 s :)
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$query =  " SELECT
                f.id fid,
                f.title as ftitle,
                f.description,
                f.order,
                f.id,
                c.id as cid,
                c.title as ctitle,
                c.order
            FROM
                forum f,
                category c
            WHERE
                c.id = f.cat_id
            ORDER BY
                c.order,
                f.order
            ";
$result = mysql_query($query);
$last = '';
while ($list = mysql_fetch_object($result))
{
    if (!($list->ctitle==$last))
        echo '<B><u> >> Category : '. $list->ctitle . ' << </U></B><BR>';
    
    echo '<B>' . $list->ftitle . '</B><BR>';
    echo '<I>'  . $list->description . '</I><BR>';
    $last = $list->ctitle;

}

[ Voor 15% gewijzigd door commeric op 26-12-2003 21:23 ]


Acties:
  • 0 Henk 'm!

  • zeroxcool
  • Registratie: Januari 2001
  • Laatst online: 04-09 19:14
Maak er één tabel van... Maak daarin iets als een catid en een parentid. Dan heb je maar één query nodig.

Je zet alles waar catid != '' een array $cat en van alles wat parentid != '' een array $fora. Dan gewoon doorlopen met een while(list() = each()).

Maak je het minste aantal queries en misschien kleine beetje meer 'rekenwerk'. Mijn voornaamste doel met mijn forum was zo min mogelijk queries te maken...

zeroxcool.net - curity.eu


Acties:
  • 0 Henk 'm!

  • supakeen
  • Registratie: December 2000
  • Laatst online: 09-09 14:42
Als je nou eens gewoon zelf gaat uittesten wat dit voor load op de server veroorzaakt e.d.

Voer je ieder script 1000x uit, slaat die tijden loads en memory usage op in een text-file en voila dan weet je het allemaal.

8)

Acties:
  • 0 Henk 'm!

  • ANdrode
  • Registratie: Februari 2003
  • Niet online
commeric schreef op 26 december 2003 @ 20:28:
PHP:
1
2
3
4
5
6
7
while ($cat_list = mysql_fetch_object($cat_result))
{
    $arr_cat[$i]['id'] = $cat_list->id;
    $arr_cat[$i]['title'] = $cat_list->title;
    $arr_cat[$i]['order'] = $cat_list->order;
    $i++;
}
kan je imho beter zo doen. Ik denk ook dat dit sneller is, want nu hoef je geen 3 vars meer te kopieren:
PHP:
1
2
3
4
5
while ($cat_list = mysql_fetch_assoc($cat_result))
{
    $arr_cat[$i][ = $cat_list;
    $i++;
}


Dit bespaart op grote schaal vast wel weer een paar milliseconden.
Ik denk trouwens dat je beter kan gaan testen met apachebench vanaf een 2e linux pc over lan naar een dedicated linux webhostingbak *op zelfde lan*, want dan zie je de reactie tijd..
Ik weet alleen niet of je het zo belangrijk vind om te weten wat het snelste is. O-)
Persoonlijk zou ik gewoon voor de meest leesbare variant gaan, want anders snap je misschien over een tijd je eigen code niet meer. (Bekijk je 1e php script maar weer eens :X)

Acties:
  • 0 Henk 'm!

  • simon
  • Registratie: Maart 2002
  • Laatst online: 11:40
Volgens mij is je probleem niet je code, maar je tabellen structuur.

[mierenneukmodus]
Btw, het mv van forum is fora, niet foras :P
[/mierenneukmodus]

|>


Acties:
  • 0 Henk 'm!

  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

tipje: do while is sneller dan while
kheb het getest hier
for: 0,76
while: 0,72
do while: 0,68

edit:
for en if verwisseld, waarom geen idee 8)7

[ Voor 24% gewijzigd door Wolfboy op 28-12-2003 21:52 ]

Blog [Stackoverflow] [LinkedIn]


Acties:
  • 0 Henk 'm!

  • Mark Wegener
  • Registratie: December 2001
  • Laatst online: 14-09 15:52
Wolfboy schreef op 26 december 2003 @ 23:48:
tipje: do while is sneller dan while
kheb het getest hier
if: 0,76
while: 0,72
do while: 0,68
kan je voorbeeld geven waarin het verschil tussen while en do..while tot uitdrukking komt?

ik mis trouwens for in je test.

Acties:
  • 0 Henk 'm!

  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Martin.Duane schreef op 27 december 2003 @ 00:55:
[...]


kan je voorbeeld geven waarin het verschil tussen while en do..while tot uitdrukking komt?

ik mis trouwens for in je test.
uhm sorry ik bedoelde for ipv. if (7(8)7 kerstdrukte denk ik ;))
hoe ik dit gebenched heb?
heel eenvoudig, gewoon laten meten hoe lang het duurt om zo'n 100.000 bewerkingen uit te voeren
ik heb niet meer exact dezelfde code als die ik toen had maar hier is een voorbeeldje (wel elke keer apart testen)
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
$max_aantal=100000;

$timer['start']=microtime();
$i=0;while($i<=$max_aantal){$i++;echo'blaat';}
$timer['stop']=microtime();
$timer['result']=$timer['stop']-$timer['start'];

echo'<br><br>'.$timer['result'];
?>
<?php
$max_aantal=100000;

$timer['start']=microtime();
for($i=0;$i<=$max_aantal;$i++)echo'blaat';
$timer['stop']=microtime();
$timer['result']=$timer['stop']-$timer['start'];

echo'<br><br>'.$timer['result'];
?>
<?php
$max_aantal=100000;

$timer['start']=microtime();
$i=0;do{$i++;echo'blaat';}while($i<=$max_aantal);
$timer['stop']=microtime();
$timer['result']=$timer['stop']-$timer['start'];

echo'<br><br>'.$timer['result'];
?>
btw niet goed kunnen testen, ik werk nu namelijk op m'n laptop en die heeft nogal wat stroombesparingstrucjes wat ervoor zorgt dat benchen de ene keer 50x langzamer ging dan de andere keer ;)

ps: hierbij kan je ook zien dat het een heel stuk sneller is ~25% om $var='test '.$dinges; te doen in plaats van $var="test $dinges";

[ Voor 14% gewijzigd door Wolfboy op 27-12-2003 03:09 ]

Blog [Stackoverflow] [LinkedIn]


Acties:
  • 0 Henk 'm!

  • MisterData
  • Registratie: September 2001
  • Laatst online: 29-08 20:29
Ik heb het zo aangepakt dat het in 1 query past :) :
code:
1
2
3
4
Tabel:
forum_id (int)
forum_name (varchar)
forum_category (Varchar)


en dan met de query:
code:
1
SELECT * FROM forums ORDER BY forum_category ASC, forum_name ASC


Vervolgens loop je door de resultaten heen en print je een category-header als die anders is dan de category van het vorige forum dat je hebt geprint.

je kunt door de query aan te passen nog wat invloed uitoefenen op de sortering. Ook kun je van de forum_category kolom een int maken en dan joinen met een eventuele categories tabel.

Het werkt bij mij erg goed maar ik geef toe dat het niet de netste oplossing is ;) Snel is het wel gelukkig :)

Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Wolfboy schreef op 26 december 2003 @ 23:48:
tipje: do while is sneller dan while
kheb het getest hier
if: 0,76
while: 0,72
do while: 0,68
Had je al gezien in wat voor context je antwoord geplaatst is? Er is een probleem dat een recursieve datatstructuur veel tijd kost omdat er voor elke categorie een nieuwe query gedaan moet worden...

En dan kom jij met enorm marginale verschillen in fors en whiles. Dat is dus een antwoord dat alleen helpt als er serieus elke promille performance nodig is die je maar kan krijgen, maar op het moment dat je nog met tuning van queries (verschillen van tientallen milliseconden of zelfs hele seconden) bezig bent heeft het weinig nut uitgebreid te gaan testen of je je loops nog marginaal sneller kunt krijgen.

Sowieso is de do heel anders, de start met een booleancheck van de while voorkomt dat je bezig gaat met lege resultaten, met een do-while moet je dat in de body van de do-while zelf nog voorkomen... En/of moet je eerst een aparte resultset-retrieval doen voor de row.
Kortom, een while is sowieso veel praktischer en op het moment dat je ze exact equivalent hebt (en ja, dat kan idd wel) zal het verschil in performance ofwel nihil zijn, of ik verwacht zelfs dat door de eenvoud de while wint... Sowieso zal ie beter leesbaar zijn op dat moment ;)
MisterData schreef op 27 december 2003 @ 10:45:
Ik heb het zo aangepakt dat het in 1 query past :) :
code:
1
2
3
4
Tabel:
forum_id (int)
forum_name (varchar)
forum_category (Varchar)
Denormaliseren om dit in één query te krijgen lijkt me niet echt verstandig, de al gevonden oplossing van de topicstarter lijkt me dan iets mooier/handiger/beter ;)

[ Voor 16% gewijzigd door ACM op 27-12-2003 10:53 ]


Acties:
  • 0 Henk 'm!

  • Johnny
  • Registratie: December 2001
  • Laatst online: 17-09 16:59

Johnny

ondergewaardeerde internetguru

Het is ook een keer getest dat mysql_fetch_object een langzame manier is om de resultaten van een query op te halen, mysql_fetch_row zou het snelste zijn.

Aan de inhoud van de bovenstaande tekst kunnen geen rechten worden ontleend, tenzij dit expliciet in dit bericht is verwoord.


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Johnny: lees de reply van ACM nog eens door, dat slaat ook op jouw opmerking

[ Voor 26% gewijzigd door .oisyn op 27-12-2003 13:17 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • BetuweKees
  • Registratie: Januari 2003
  • Laatst online: 15-07 20:53

BetuweKees

Flipje uit Tiel

als je maar een level diep gaat (dus een parent met een child, daaronder niks) kan je dan niet gewoon een self join doen?


[edit]
hmm.. heb even te snel gelezen denk ik zoiets doe je bij je derde manier al.. Heb je al gekeken wat er met je performace gebeurt als je er een left join van maakt ipv een equi join zoals je nu met where doet?

[ Voor 48% gewijzigd door BetuweKees op 27-12-2003 15:41 ]

Through meditation I program my heart to beat breakbeats and hum basslines on exhalation -Blackalicious || *BetuweKees was AFK; op de fiets richting China en verder

Pagina: 1