[PHP] Overzichtelijkheid vs. snelheid

Pagina: 1
Acties:
  • 251 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Beste mensen,

ik zit met een dilemma wat betreft de overzichtelijkheid en snelheid van m'n code. Ik heb een User class met daarin user-specifieke variabelen en methoden. Tot nu toe gaat dit allemaal goed. De manier waarop deze Users worden geinitieerd is als volgt:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php

// User-class, gereduceerd tot construct en 2 variabelen

class User {
    private $ID;
    private $username;
    private $passwordHash;

    public function __construct($ID) {
        $db = Database::getInstance();
        $db->execQuery("SELECT username,passwordHash FROM users WHERE ID = $ID");
        $user = $db->fetchObject();
        $this->ID = $ID;
        $this->username = $user->username;
        $this->passwordHash = $user->passwordHash;
    }
}

?>


Nu kan ik dus makkelijk een User object aanmaken door gewoon new User($ID) aan te roepen. Het maakt de code erg overzichtelijk en onderhoudbaar.

Ik heb nu ook een PrivateMessage class, waarbij ik ook moet werken met Users (namelijk de zender en ontvanger). Een PrivateMessage object wordt op dezelfde manier als een User geinitieerd (dus ID meegeven en de class zoekt de rest op in de database). Ook dit is overzichtelijk.

Maar het probleem is, dat ik nu wel erg veel queries krijg, wat dus (neem ik aan) wel effect heeft op de uiteindelijke snelheid van m'n website. Is het niet beter om de PrivateMessage class gelijk in dezelfde query alle info van de users ook op te zoeken, en dan de users zo instantieren:

PHP:
1
2
3
4
5
public function __construct($ID, $username, $passwordHash) {
    $this->ID = $ID;
    $this->username = $username;
    $this->passwordHash = $passwordHash;
}


Aangezien ik veel user-variabelen heb wordt het dan niet erg overzichtelijk/onderhoudbaar, maar het komt wel de snelheid ten goede (neem ik aan) aangezien ik dan 3 queries reduceer tot 1. Wat vinden jullie hiervan?

Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Ik zou het sowieso zo proberen te ontwerpen dat je geen queries binnen je domein objecten doet. Hiervoor kun je het beste een aparte class maken, UserDB of UserRepository bijvoorbeeld. Die kun je dan weer een methode getUserByID($ID) geven waarin je een query uitvoert en een bijbehorend object initialiseert. Zo kun je dit soort optimalisaties altijd later nog inbouwen, mocht het nodig zijn.

Zoals altijd: eerst meten dan pas optimaliseren. Dus programmeer het eerst gewoon zo net en gestructureerd mogelijk (je moet performance natuurlijk wel een klein beetje in het achterhoofd houden, maar je begrijpt wat ik bedoel), dan kun je later, nadat je er een profiler overheen hebt gehaald, zo nodig wat optimalisaties toepassen.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Oke, ik heb nu een UserRepository class met de getByID method aangemaakt. Maar dan heb ik dus ook een MessageRepository class nodig, om op dezelfde manier Message classes te krijgen? En hoe moet ik dan de MessageRepository::getByID method implementeren? Aangezien mijn Message class een verwijzing naar 2 User objecten heeft (zender en ontvanger), heb ik dus ook een manier nodig om die twee User objecten te instantieren. Moet ik daar de UserRepository class voor gebruiken, of is het slimmer om in dezelfde Message-query gelijk de User-objecten mee te nemen en in de MessageRepository class dus ook de 2 Users te instantieren?

(hoop dat het een beetje duidelijk is zo :P)

Acties:
  • 0 Henk 'm!

  • SchizoDuckie
  • Registratie: April 2001
  • Laatst online: 18-02 23:12

SchizoDuckie

Kwaak

zoek eens op o/r mapper ;)

Stop uploading passwords to Github!


Acties:
  • 0 Henk 'm!

  • sky-
  • Registratie: November 2005
  • Niet online

sky-

qn nna 👌

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php 

// User-class, gereduceerd tot construct en 2 variabelen 

class User { 
    private $ID; 
    private $username; 
    private $passwordHash; 

    public function __construct($ID) { 
        $db = Database::getInstance(); 
        $db->execQuery("SELECT username,passwordHash FROM users WHERE ID = ".$ID); 
        $user = $db->fetchObject(); 
        $this->ID = $ID; 
        $this->username = $user->username; 
        $this->passwordHash = $user->passwordHash; 
    } 
} 

?>


Leuk, je programmeert in "php5" stijl, maar je haalt variabelen niet buiten je quotes.. foei :)

don't be afraid of machines, be afraid of the people who build and train them.


Acties:
  • 0 Henk 'm!

  • SchizoDuckie
  • Registratie: April 2001
  • Laatst online: 18-02 23:12

SchizoDuckie

Kwaak

k8skaaay schreef op dinsdag 01 mei 2007 @ 21:03:
Leuk, je programmeert in "php5" stijl, maar je haalt variabelen niet buiten je quotes.. foei :)
waar heb je het over :?

Stop uploading passwords to Github!


Acties:
  • 0 Henk 'm!

  • b19a
  • Registratie: September 2002
  • Niet online
Zoek eens op SQL Injection.

Acties:
  • 0 Henk 'm!

  • SchizoDuckie
  • Registratie: April 2001
  • Laatst online: 18-02 23:12

SchizoDuckie

Kwaak

Dat gaat nergens over in deze context imo.

Stop uploading passwords to Github!


Acties:
  • 0 Henk 'm!

  • TweakerNummer
  • Registratie: September 2001
  • Niet online
TS:
code:
1
$db->execQuery("SELECT username,passwordHash FROM users WHERE ID = $ID");

Hij:
code:
1
$db->execQuery("SELECT username,passwordHash FROM users WHERE ID = ".$ID);


Let op $ID. Wat het voordeel hiervan is zou ik niet weten, want er kan nog steeds vanalles en nog wat fout gaan zolang je $ID niet checked.Ach op zo een manier. Ja, daarin geef ik je helemaal gelijk @mithras.

[ Voor 25% gewijzigd door TweakerNummer op 01-05-2007 21:40 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
k8skaaay schreef op dinsdag 01 mei 2007 @ 21:03:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php 

// User-class, gereduceerd tot construct en 2 variabelen 

class User { 
    private $ID; 
    private $username; 
    private $passwordHash; 

    public function __construct($ID) { 
        $db = Database::getInstance(); 
        $db->execQuery("SELECT username,passwordHash FROM users WHERE ID = ".$ID); 
        $user = $db->fetchObject(); 
        $this->ID = $ID; 
        $this->username = $user->username; 
        $this->passwordHash = $user->passwordHash; 
    } 
} 

?>


Leuk, je programmeert in "php5" stijl, maar je haalt variabelen niet buiten je quotes.. foei :)
Dank voor de suggestie, echter een beetje irrelevant; de code heb ik een beetje versimpeld, dit is de oorspronkelijke:
PHP:
1
$this->db->execQuery('SELECT `ID`, `username`, `passwordHash`, `email`, `realName`, `dateOfBirth`, `gender`, `location`, `memberSince`, `lastVisit` FROM `users` WHERE `ID` = '.$this->db->smartQuote($ID));

Wel redelijk veilig dacht ik zo.

Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
TweakerNummer schreef op dinsdag 01 mei 2007 @ 21:28:
[...]

[...]
Let op $ID. Wat het voordeel hiervan is zou ik niet weten, want er kan nog steeds vanalles en nog wat fout gaan zolang je $ID niet checked.
In principe werkt het inderdaad, en de snelheidswinst is minimaal. Echter bestaat er ook nog iets als "richtlijn" of in die trant. Voor nette php5 "stijl" raden ze dus het buiten quotes halen aan.

@TS: Ik zou eerst eens gaan testen met groottes van userbases die je in gedachten hebt. Je kan lastig bij voorbaat al zeggen of deze queries langzaam worden en zo de beperkende factor vormen voor je snelheid :)

Volgens mij maakt het niets uit. Om $username en $passwordHash mee te geven moet je die wel weten. En hoe kom je dat te weten? Juist, met een query naar een database. Het heeft dus eigenlijk geen zin, aangezien je alleen de query naar voren in je proces brengt en zo misschien wel meer functies en queries moet aanroepen dan dat je nu al doet :)

Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 20-09 22:44

MBV

Verwijderd schreef op dinsdag 01 mei 2007 @ 20:30:
Oke, ik heb nu een UserRepository class met de getByID method aangemaakt. Maar dan heb ik dus ook een MessageRepository class nodig, om op dezelfde manier Message classes te krijgen? En hoe moet ik dan de MessageRepository::getByID method implementeren? Aangezien mijn Message class een verwijzing naar 2 User objecten heeft (zender en ontvanger), heb ik dus ook een manier nodig om die twee User objecten te instantieren. Moet ik daar de UserRepository class voor gebruiken, of is het slimmer om in dezelfde Message-query gelijk de User-objecten mee te nemen en in de MessageRepository class dus ook de 2 Users te instantieren?

(hoop dat het een beetje duidelijk is zo :P)
Volgens mij kan je daar toch je UserRepository voor gebruiken? Het lijkt erop dat je Message-class ook iets is wat sterk persoons-georienteerd is, dus dat zou geen probleem moeten zijn. Gewoon 2 functies in de UserRepository maken: getPersonById en getMessageByIds($person1, $person2) of zoiets.

Nog een performance-tip trouwens, als je vaak dezelfde personen aanmaakt in dezelfde sessie: maak je userRepository een singleton, en bewaar de objecten die je hebt aangemaakt. Als je dan nog een keer om hetzelfde object vraagt, kan je die uit je array ofzo halen :)

@mithras: elke query die je richting database slingert zorgt voor meer delay. Hoe minder querys hoe beter (en je pagina komt minder vol te staan als je database-debug aan zet :+)

[ Voor 6% gewijzigd door MBV op 01-05-2007 21:38 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
mithras schreef op dinsdag 01 mei 2007 @ 21:35:
@TS: Ik zou eerst eens gaan testen met groottes van userbases die je in gedachten hebt. Je kan lastig bij voorbaat al zeggen of deze queries langzaam worden en zo de beperkende factor vormen voor je snelheid :)
Dat wordt heel moeilijk, aangezien ik niet aan een limiet denk. Ik wil dus de snelst mogelijke oplossing hebben.
Volgens mij maakt het niets uit. Om $username en $passwordHash mee te geven moet je die wel weten. En hoe kom je dat te weten? Juist, met een query naar een database. Het heeft dus eigenlijk geen zin, aangezien je alleen de query naar voren in je proces brengt en zo misschien wel meer functies en queries moet aanroepen dan dat je nu al doet :)
Oke, maar heeft het dan zin om alles in 1 query te stoppen (dat wordt dus een flinke query met een join) of gewoon een query voor de message, eentje voor de fromUser en een voor de toUser?
MBV schreef op dinsdag 01 mei 2007 @ 21:35:
[...]

Volgens mij kan je daar toch je UserRepository voor gebruiken? Het lijkt erop dat je Message-class ook iets is wat sterk persoons-georienteerd is, dus dat zou geen probleem moeten zijn. Gewoon 2 functies in de UserRepository maken: getPersonById en getMessageByIds($person1, $person2) of zoiets.
Er komen later ook nog contacten en foto's bij. Moet ik UserRepository daar ook voor gebruiken? Lijkt mij dat het dan een beetje verwatert.

[ Voor 21% gewijzigd door Verwijderd op 01-05-2007 22:09 ]


Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
MBV schreef op dinsdag 01 mei 2007 @ 21:35:
[...]

@mithras: elke query die je richting database slingert zorgt voor meer delay. Hoe minder querys hoe beter (en je pagina komt minder vol te staan als je database-debug aan zet :+)
Dat is precies wat ik probeer te zeggen: je kan van tevoren wel username en passwordhash meegeven, maar die moet je wel uit de database halen, dus betekent het alsnog een query, en waarschijnlijk zelfs meer dan met de huidige oplossing. De performancewinst is er dus niet of het vertraagd het proces zelfs :)

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
-laat maar-

[ Voor 91% gewijzigd door Verwijderd op 01-05-2007 22:28 ]


Acties:
  • 0 Henk 'm!

  • froggie
  • Registratie: November 2001
  • Laatst online: 20-11-2024

froggie

Kwaaak

Verwijderd schreef op dinsdag 01 mei 2007 @ 22:06:
Oke, maar heeft het dan zin om alles in 1 query te stoppen (dat wordt dus een flinke query met een join) of gewoon een query voor de message, eentje voor de fromUser en een voor de toUser?
Vaak zijn drie simpele queries sneller dan een grote(re), complexe query met een join. Mijn voorkeur zou voorlopig uitgaan naar losse queries tenzij je met een benchmark kunt onderbouwen dat een enkele complexere query sneller is.

Los daarvan krijg ik het idee dat je jezelf en je code in allerlei bochten probeert te wringen om het laatste beetje extra performance te persen uit een applicatie die je nog niet eens hebt zien werken. Kom eerst tot een werkende applicatie en ga dan, wanneer dat nodig is, op zoek naar performance verbeteringen. Op dat moment heb je namelijk cijfers om dingen mee te onderbouwen.

Ik bedoel hiermee niet dat je nu blind moet gaan coden zonder na te denken over de performance. Zorg dat je daadwerkelijk de mogelijkheid in je code houdt om dingen te verbeteren (modulariteit). Maar op dit moment lijkt een netjes geschreven en werkende applicatie me belangrijker dan snelheid.

offtopic:
Kijk eens naar Ruby on Rails, of als je in PHP wilt blijven werken naar een van de PHP MVC frameworks. Dergelijke frameworks handelen dit soort problemen voor je af zodat jij je bezig kunt houden met dat wat je leuk vind, namelijk inventieve dingen bouwen.

Acties:
  • 0 Henk 'm!

  • Morax
  • Registratie: Mei 2002
  • Laatst online: 20:32
Wat de topicstarter hier voornamelijk bedoelt, is het volgende. De manier die voorgesteld is, is om repositories te gebruiken, maar met het voorbeeld krijg je dan het probleem, dat bij het ophalen van een message ook 2 user classes moeten worden geinstantieerd.

Dat zijn dus 3 queries per message. Stel dat het hier gaat om messages op een nieuwsbericht waar 15 keer op gereageerd is, heb je dus 3 x 15 = 45 queries op je pagina!

45 makkelijke queries vs 1 query met 2 joins. Wat gaat er winnen denk je? :)

What do you mean I have no life? I am a gamer, I got millions!


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 20-09 22:44

MBV

mithras schreef op dinsdag 01 mei 2007 @ 22:16:
[...]
Dat is precies wat ik probeer te zeggen: je kan van tevoren wel username en passwordhash meegeven, maar die moet je wel uit de database halen, dus betekent het alsnog een query, en waarschijnlijk zelfs meer dan met de huidige oplossing. De performancewinst is er dus niet of het vertraagd het proces zelfs :)
Dat is dus niet waar, als je het implementeert op de manier die ik bedoel. Je slaat in je singleton UserDB de opgevraagde gegevens op in een associatieve array (hashmap), en geeft ze aan het object in de constructor als iemand je method aanroept om dat object aan te maken. Welke gegevens je opvraagt kan je op 2 manieren bepalen: een functie loadUserData, die als argument een array van userid's heeft, of elke keer dat iemand getPersonById aanroept een query die je opslaat.

Als je wilt schrijf ik morgen ofzo wel een voorbeeldje, maar ik denk dat je er zo ook wel uitkomt ;)

@TS: ik zou dat wel doen. Je UserDB object gebruik je voor alle toegang tot de database die betrekking heeft op de gebruikers, en op die manier kan je al je gegevens in 1 keer uit de database laten halen. Als je 5 klasses voor je databasetoegang schrijft moet je 5x dezelfde query uitvoeren. Nu heb je het voordeel dat je alle databasetoegang op 1 punt concentreert, en dat je bij 1 wijziging alle functies kan laten profiteren :)
Dat helpt dus ook bij je dilemma of je alles in 1 query moet zetten (ben ik helemaal voor) of 1.337 losse queries. Als je het in 1 centraal object zet kan je dat heel snel omschakelen, zonder dat je je systeem aanpast. Je zou het zelfs kunnen omzetten naar LDAP DON'T!, zonder de rest van je systeem aan te passen. Flexibiliteit, onderhoudbaarheid, wat wil je nog meer? ;)

Een andere oplossing, die ik niet aan zou raden, is om een singleton DatabaseXS object te maken, die door 5 singleton klasses wordt geladen (UserDB, MessageDB, dat soort dingen). Dat wordt pas een onoverzichtelijke brij :X

Acties:
  • 0 Henk 'm!

  • OxiMoron
  • Registratie: November 2001
  • Laatst online: 08-07 14:27
Als je echt op snelheid gaat letten moet je ook zoveel mogelijk de enkel quote ' gebruiken.
Tekst met dubbel quote " wordt namelijk nog geparsed door php, enkel quote niet.

Albert Einstein: A question that sometime drives me hazy: Am I or are the others crazy?


Acties:
  • 0 Henk 'm!

  • robbert
  • Registratie: April 2002
  • Laatst online: 20:37
OxiMoron schreef op woensdag 02 mei 2007 @ 08:58:
Als je echt op snelheid gaat letten moet je ook zoveel mogelijk de enkel quote ' gebruiken.
Tekst met dubbel quote " wordt namelijk nog geparsed door php, enkel quote niet.
Dit zijn wel optimalisaties van een totaal ander niveau. 1000 queries ipv 1 of 2 levert je een stuk meer snelheidswinst dan die enkele quotes ooit op zullen leveren.

Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 20-09 22:44

MBV

OxiMoron schreef op woensdag 02 mei 2007 @ 08:58:
Als je echt op snelheid gaat letten moet je ook zoveel mogelijk de enkel quote ' gebruiken.
Tekst met dubbel quote " wordt namelijk nog geparsed door php, enkel quote niet.
Wil jij me een real-life voorbeeld geven waarbij dat verschil meer dan 0.1% uitmaakt op de totale response-tijd? Real-life als in: je maakt gebruik van een database, een paar hash-maps en een paar objecten, en je hebt geen loopje die 10.000 keer een echo doet ;) Oh ja, vergeet niet dat aan het eind van 1 op de 5 echo-statements een newline moet komen :P

[ Voor 7% gewijzigd door MBV op 02-05-2007 12:05 ]


Acties:
  • 0 Henk 'm!

  • Upsal
  • Registratie: Mei 2005
  • Laatst online: 27-08-2024
Morax schreef op dinsdag 01 mei 2007 @ 23:47:
Wat de topicstarter hier voornamelijk bedoelt, is het volgende. De manier die voorgesteld is, is om repositories te gebruiken, maar met het voorbeeld krijg je dan het probleem, dat bij het ophalen van een message ook 2 user classes moeten worden geinstantieerd.

Dat zijn dus 3 queries per message. Stel dat het hier gaat om messages op een nieuwsbericht waar 15 keer op gereageerd is, heb je dus 3 x 15 = 45 queries op je pagina!

45 makkelijke queries vs 1 query met 2 joins. Wat gaat er winnen denk je? :)
Nou, ik weet nog niet zo zeker of de JOIN query gaat winnen. Eerst dacht ik ook dat je met zo min mogelijk queries altijd beter af bent (theoretisch beredeneert). Echter zoals froggie al zegt kunnen simpele queries ook vaak sneller zijn. Wat sneller is, is afhankelijk van de situatie (welke tabellen, hoe groot de pagina elke keer is, en waar je op selecteert (id, geindexeerde kolom, niet geindexeerde kolom).
Met behulp van benchmarkprogrammas zoals xdebug (in combinatie met WinCacheGrind of KCacheGrind) kun je dit in één oogopslag zien. Je zult misschien versteld staan wat 't resultaat is.

Acties:
  • 0 Henk 'm!

  • Morax
  • Registratie: Mei 2002
  • Laatst online: 20:32
Upsal schreef op woensdag 02 mei 2007 @ 12:51:
[...]


Nou, ik weet nog niet zo zeker of de JOIN query gaat winnen. Eerst dacht ik ook dat je met zo min mogelijk queries altijd beter af bent (theoretisch beredeneert). Echter zoals froggie al zegt kunnen simpele queries ook vaak sneller zijn. Wat sneller is, is afhankelijk van de situatie (welke tabellen, hoe groot de pagina elke keer is, en waar je op selecteert (id, geindexeerde kolom, niet geindexeerde kolom).
Met behulp van benchmarkprogrammas zoals xdebug (in combinatie met WinCacheGrind of KCacheGrind) kun je dit in één oogopslag zien. Je zult misschien versteld staan wat 't resultaat is.
Ik heb net een testje gedraait, en daarvan is dit het resultaat:

Resultaat test 1 (met join) (24 comments) (1 queries): 0.000271081924438

Resultaat test 2 (zonder join) (24 comments) (25 queries): 0.0027627945

De manier zonder joins is toch een factor 10 (!!!) langzamer!

What do you mean I have no life? I am a gamer, I got millions!


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 20-09 22:44

MBV

Upsal schreef op woensdag 02 mei 2007 @ 12:51:
[...]


Nou, ik weet nog niet zo zeker of de JOIN query gaat winnen. Eerst dacht ik ook dat je met zo min mogelijk queries altijd beter af bent (theoretisch beredeneert). Echter zoals froggie al zegt kunnen simpele queries ook vaak sneller zijn. Wat sneller is, is afhankelijk van de situatie (welke tabellen, hoe groot de pagina elke keer is, en waar je op selecteert (id, geindexeerde kolom, niet geindexeerde kolom).
Met behulp van benchmarkprogrammas zoals xdebug (in combinatie met WinCacheGrind of KCacheGrind) kun je dit in één oogopslag zien. Je zult misschien versteld staan wat 't resultaat is.
Ehm, je vergeet 1 belangrijk onderdeel: waar staat de SQL-server? Op mijn werk is dat een andere bak, dat betekent TCP/IP verkeer heen en weer, wat altijd minstens 10ms duurt. En dat voor elke query die je doet... Dus dat is ook de vraag aan Morax: waar staat je SQL-server?

Acties:
  • 0 Henk 'm!

  • Upsal
  • Registratie: Mei 2005
  • Laatst online: 27-08-2024
Morax schreef op woensdag 02 mei 2007 @ 14:13:
[...]


Ik heb net een testje gedraait, en daarvan is dit het resultaat:

Resultaat test 1 (met join) (24 comments) (1 queries): 0.000271081924438

Resultaat test 2 (zonder join) (24 comments) (25 queries): 0.0027627945

De manier zonder joins is toch een factor 10 (!!!) langzamer!
Ik heb het ook even getest, en ik kom tot een ander resultaat:

Resultaat test 1 (met join) (24 comments) (1 queries): 0.0266320705414
Resultaat test 2 (zonder join) (24 comments) (25 queries): 0.0155460834503

Maar als ik een keer op F5 druk dan krijg ik:

Resultaat test 1 (met join) (24 comments) (1 queries): 0.00247311592102
Resultaat test 2 (zonder join) (24 comments) (25 queries): 0.0166809558868

Misschien dat dit laatste ook gebeurd is bij jouw meeting.

Dit komt door de query-cache in MySQL, waardoor hij bij test 2 langzamer is omdat hij meer aanvragen moet indienen, terwijl het resultaat bij test 1 in feite al klaar staat.

@MBV: dat is inderdaad een belangrijk punt. Mijn aanname was een MySQL server op localhost.

Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 20-09 22:44

MBV

Upsal schreef op woensdag 02 mei 2007 @ 16:16:
[...]


Ik heb het ook even getest, en ik kom tot een ander resultaat:
[knip]

@MBV: dat is inderdaad een belangrijk punt. Mijn aanname was een MySQL server op localhost.
Jongens, jongens, jongens. Waarom testen jullie dit 1x? Dit soort dingen moet je, omdat de tijd zo belachelijk kort is, op zijn minst 100 keer achter elkaar uitvoeren, dan krijg je een betrouwbare meting. Zeker als je daar tussenin iets van 'flush cache' zet, of gewoon je tabel vult met 1000 random waardes en daar een paar random uit pikt.

En zoals je zelf al aangeeft: met mysql op de localhost zal het minder uitmaken. Stel je dus eens voor dat je gaat upscalen omdat er ineens 100.000 bezoekers komen, en dus 2 html-servers neerzet voor 1 database-server. Als je doet wat ik suggereer kan je voor nu je 25 simpele queries uitvoeren. Zodra dat een beperking gaat vormen kan je dat eenvoudig omzetten :). En zeg nu zelf: 5x dezelfde gegevens opvragen is niet handig, toch? ;)

Acties:
  • 0 Henk 'm!

  • Morax
  • Registratie: Mei 2002
  • Laatst online: 20:32
Hmmm, ik had ff snel een testje gebouwd ja, ik zal vanavond wat beter testen :)
Het is overigens getest op een bak met apache en mysql op dezelfde bak.

Is er overigens een manier om MySQL in dat geval te dwingen om zijn cache niet te gebruiken (puur om te testen, in mijn echte omgeving ga ik dat natuurlijk niet doen :P)

Ik weet alleen niet of ik zo snel een externe MySQL server heb om te testen...

Edit:
Nieuwe resultaten:
code:
1
2
3
 Resultaat van 1000 testruns:
Gemiddelde tijd test 1 (met join, 1 queries):     0.000232776403427
Gemiddelde tijd test 2 (zonder join, 25 queries):   0.0027820224762


Dit is dan nog wel inclusief MySQL cache, en met Webserver en DB op 1 bak.

[ Voor 26% gewijzigd door Morax op 02-05-2007 17:01 ]

What do you mean I have no life? I am a gamer, I got millions!


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 20-09 22:44

MBV

http://dev.mysql.com/tech...es/mysql-query-cache.html

Volgens mij dus:
SQL:
1
2
flush status;
reset query cache;


Maar dat is al weer ver offtopic. Mijn antwoord op de vraag "Wat moet je kiezen, overzichtelijkheid of snelheid?" lijkt me trouwens: Overzichtelijk is vaak ook het snelste ;)

Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Of: overzichtlijk geeft je later meer mogelijkheden om het sneller te maken. Zo zie ik het altijd.

Overzichtelijk vind ik een beetje een raar woord eigenlijk. De code die de TS overzichtelijk vond, vind ik trouwens juist niet overzichtelijk. Het is naar mijn mening inleveren op gestructureerd werken ten behoeve van een extra class. Je voegt het beheren van de persistentie van een domein object en het domein object zelf samen, wat uiteindelijk kan resulteren in vrij onoverzichtelijke code. Taken moeten duidelijk gescheiden zijn, zo behoudt je het overzicht veel beter.

Nog een paar tips:

- Werk zaken waarvan je verwacht dat ze mogelijk langzaam gaan presteren weg in een eigen component of achter een interface. Zo kun je verschillende implementaties proberen en gemakkelijk optimaliseren.

- Probeer zo min mogelijk (niet overdrijven natuurlijk) herhalende code te schrijven. Als je dan profiled, en je komt een functie tegen die langzaam presteert, dan weet je zeker dat je na een optimalisatie nergens anders deze wijzingen hoeft toe te passen.

- Probeer de oorzaak van de bottleneck goed te begrijpen als je er een tegenkomt. Deze kennis kun je later goed gebruiken.

[ Voor 84% gewijzigd door Michali op 02-05-2007 17:43 ]

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • froggie
  • Registratie: November 2001
  • Laatst online: 20-11-2024

froggie

Kwaaak

Als jullie zo fanatiek aan het benchen gaan en de query cache willen meenemen in je resultaat (per slot van rekening zul je die in een real world situatie ook gebruiken) houdt dan het volgende in het achterhoofd:

de query cache houdt het resultaat van een query slechts vast zolang de tabel/tabellen waarop deze queries gedaan zijn ongewijzigd blijft. Wanneer je dus een complexe join doet over meerdere tabellen die regelmatig tot snel veranderen dan is in een real world situatie de kans dat je het resultaat van die complexe query een tweede keer uit de query cache kunt halen klein, doordat deze in de tussentijd waarschijnlijk geflushed is. Op dat moment kost het meer tijd om iedere keer die enkele complexe query uit te voeren ipv een serie simpele queries (waarvan het resultaat van sommige van deze queries misschien zelfs nog in de cache zit).

Acties:
  • 0 Henk 'm!

  • Morax
  • Registratie: Mei 2002
  • Laatst online: 20:32
froggie schreef op woensdag 02 mei 2007 @ 19:44:
Als jullie zo fanatiek aan het benchen gaan en de query cache willen meenemen in je resultaat (per slot van rekening zul je die in een real world situatie ook gebruiken) houdt dan het volgende in het achterhoofd:

de query cache houdt het resultaat van een query slechts vast zolang de tabel/tabellen waarop deze queries gedaan zijn ongewijzigd blijft. Wanneer je dus een complexe join doet over meerdere tabellen die regelmatig tot snel veranderen dan is in een real world situatie de kans dat je het resultaat van die complexe query een tweede keer uit de query cache kunt halen klein, doordat deze in de tussentijd waarschijnlijk geflushed is. Op dat moment kost het meer tijd om iedere keer die enkele complexe query uit te voeren ipv een serie simpele queries (waarvan het resultaat van sommige van deze queries misschien zelfs nog in de cache zit).
Dat is ook de reden dat ik de cache wil uitsluiten van deze benchmark :) Omdat mijn query met join waarschijnlijk nog in de cache zit, en misschien daarom wel sneller is ;)

Edit:
In deze benchmark update ik een record in zowel de User tabel als de Comment tabel, om te zorgen dat de cache niet meer geldig is, dit zijn de resultaten:

code:
1
2
3
 Resultaat van 1000 testruns:
Gemiddelde tijd test 1 (met join, 1 queries):   0.000760713577271
Gemiddelde tijd test 2 (zonder join, 25 queries): 0.00307276725769


code:
1
2
3
 Resultaat van 1000 testruns:
Gemiddelde tijd test 1 (met join, 1 queries):   0.000761910200119
Gemiddelde tijd test 2 (zonder join, 25 queries): 0.00385340476036

[ Voor 18% gewijzigd door Morax op 02-05-2007 21:06 ]

What do you mean I have no life? I am a gamer, I got millions!


Acties:
  • 0 Henk 'm!

Verwijderd

Het is uiteraard vrij logisch dat een goede join vele malen sneller is dan dat geneuzel in php. Dat geneuzel is namelijk een join faken in een worst-case scenario :) Je maakt daarmee alle optimalisaties van een database onmogelijk (bijvoorbeeld een gedeelde index over een foreign-key constraint). Dat is natuurlijk nog los van de eerdere genoemde nutteloze roundtrips naar je database.

Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 20-09 22:44

MBV

Michali schreef op woensdag 02 mei 2007 @ 17:34:
Of: overzichtlijk geeft je later meer mogelijkheden om het sneller te maken. Zo zie ik het altijd.

Overzichtelijk vind ik een beetje een raar woord eigenlijk. De code die de TS overzichtelijk vond, vind ik trouwens juist niet overzichtelijk. Het is naar mijn mening inleveren op gestructureerd werken ten behoeve van een extra class. Je voegt het beheren van de persistentie van een domein object en het domein object zelf samen, wat uiteindelijk kan resulteren in vrij onoverzichtelijke code. Taken moeten duidelijk gescheiden zijn, zo behoudt je het overzicht veel beter.

Nog een paar tips:

- Werk zaken waarvan je verwacht dat ze mogelijk langzaam gaan presteren weg in een eigen component of achter een interface. Zo kun je verschillende implementaties proberen en gemakkelijk optimaliseren.

- Probeer zo min mogelijk (niet overdrijven natuurlijk) herhalende code te schrijven. Als je dan profiled, en je komt een functie tegen die langzaam presteert, dan weet je zeker dat je na een optimalisatie nergens anders deze wijzingen hoeft toe te passen.

- Probeer de oorzaak van de bottleneck goed te begrijpen als je er een tegenkomt. Deze kennis kun je later goed gebruiken.
Ik heb het niet beter kunnen zeggen, maar wat jij hier opschrijft is wat ik al de hele tijd bedoel :)

offtopic:
hebben we trouwens inmiddels de TS weggejaagd ofzo, met al dat geneuzel over optimalisaties? :$

Acties:
  • 0 Henk 'm!

  • Gwaihir
  • Registratie: December 2002
  • Niet online
Dat zijn - dacht ik - zelf ook forse acties. Verstoren je profiling dus.

Denk meer aan: SET SESSION query_cache_type = OFF; of SQL_NO_CACHE in elke SELECT query.

Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 20-09 22:44

MBV

Birdie schreef op woensdag 02 mei 2007 @ 23:21:
[...]

Dat zijn - dacht ik - zelf ook forse acties. Verstoren je profiling dus.

Denk meer aan: SET SESSION query_cache_type = OFF; of SQL_NO_CACHE in elke SELECT query.
Ehm, je meet de tijd dat de query-execution duurt, en je negeert alle andere tijd, toch? Hoe wil je er anders voor zorgen dat de tijd die je for-loop o.i.d. nodig heeft niet je resultaat beinvloed?
Daarentegen gaat de hele test wel sneller met dat soort dingen, dus wel handig om te weten ;)
Pagina: 1