Verwijderd schreef op 16 september 2003 @ 13:35:
je kunt je pagina eens timen, maar ik denk niet dat je met cachen al te veel snelheidswinst zult behalen. MySQL is al zo ontzettend snel dat je je tijd beter kunt besteden aan het optimaliseren van je queries.
Niet helemaal akkoord! Inderdaad moet je in de eerste plaats je aandacht besteden aan het optimaliseren van queries, maar met het cachen van resultaten kan je WEL snelheidswinst behalen!
Een tijdje geleden was hier een soortgelijk topic (gebruik de search maar eens) over het cachen van resultaten van queries in files. ACM had toen een test/benchmark uitgevoerd, waaruit bleek dat het opvragen van een array (opgeslagen met de serialize()-functie) in een file zelfs tot
10 keer sneller kan zijn dan de query opnieuw uit te voeren en zo de array opnieuw samen te stellen! Ik had de benchmark toen overgetypt (en een beetje aangepast) en heb deze nog:
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
95
96
97
98
99
| <?
error_reporting(E_ALL);
$totalTests = 100;
$totalEntries = 100;
function getTime()
{
list($usec, $sec) = explode(" ", microtime());
return ( (float) $usec + (float) $sec );
}
/*********/
/* Files */
/*********/
$arrayToFile = array();
for ($i = 0; $i < $totalEntries; $i++)
{
$arrayToFile[$i]['id'] = $i + 1;
$arrayToFile[$i]['name'] = "Napoleon";
}
$file = fopen("bench1", "w+");
if ($file)
fwrite($file, serialize($arrayToFile));
/* start benchmark */
$startTime = getTime();
for ($i = 0; $i < $totalTests; $i++)
{
if (file_exists("bench1"))
{
$result = array();
$result = unserialize(file_get_contents("bench1"));
// print_r($result);
}
}
echo "Files: " . (getTime() - $startTime) . "\n";
/* clean up */
unlink("bench1");
/*********/
/* MySQL */
/*********/
$dbConn = mysql_connect("localhost", "root");
mysql_select_db("Peter");
mysql_query("DROP TABLE IF EXISTS bench1");
mysql_query("CREATE TABLE bench1 (id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, name CHAR(8) NOT NULL , PRIMARY KEY(id))");
for ($i = 0; $i < $totalEntries; $i++)
mysql_query("INSERT INTO bench1 VALUES ('', 'Napoleon')");
mysql_close($dbConn);
/* start benchmark */
$startTime = getTime();
for ($i = 0; $i < $totalTests; $i++)
{
/* connect to database and select database */
$dbConn = mysql_connect("localhost", "root");
mysql_select_db("Peter");
/* execute query */
$queryResult = mysql_query("SELECT id, name FROM bench1");
/* get results */
if ($queryResult && mysql_num_rows($queryResult) > 0)
{
$result = array();
while ($row = mysql_fetch_assoc($queryResult))
$result[] = $row;
// print_r($result);
}
/* close connection */
mysql_close($dbConn);
}
echo "MySQL: " . (getTime() - $startTime) . "\n";
/* clean up */
$dbConn = mysql_connect("localhost", "root");
mysql_select_db("Peter");
mysql_query("DROP TABLE bench1");
?> |
Op mijn PC gaf dat volgend resultaat:
Files: 0.0298789739609
MySQL: 0.193956971169
Je moet maar eens spelen met $totalEntries en $totalTests bovenaan, maar zelf heb ik nog geen situatie kunnen vinden waarbij MySQL ofwel in de buurt ofwel sneller is als files. Ik heb wel opgemerkt dat hoe hoger je $totalEntries zet, hoe kleinder de factor wordt, maar op 9999 had ik nog steeds een verschil van factor 3.
Wat ik hieruit concludeer:
- Files zijn sneller, ondanks de tijdrovende unserialize() die je moet toepassen om je array te verkrijgen!
- Dit is een maar een heel simpel voorbeeldje: de gebruikte query omslaat slechts 1 tabel (dus geen joins bijvoorbeeld), er zijn geen condities (geen WHERE), sortering (geen ORDER) of groepering (geen GROUP) => bij ingewikkelde queries (ja inderdaad, dat zijn de queries die jij wil cachen/optimaliseren/...) zal MySQL (waarschijnlijk) trager worden dan hij op deze query presteert,
maar bij files blijft de snelheid (relatief dan) gelijk!
Nu wil jij cachen in sessies (wat eigenlijk ook files zijn!) en zal dat volgens mij ook sneller zijn, hoewel ik hier geen ervaring mee heb. Je kan deze benchmark misschien proberen aan te passen, en zien wat het geeft? (lijkt me niet veel werk).
Je moet wel 1 ding goed in het oog houden: ga je op het niveau van de user of van de server cachen? Het is zeker niet slim om een query die niet afhankelijk is van de user, te cachen in sessies => als je dan 100 users hebt, heb je 100 keer dezelfde query gecacht! (stel je voor dat GOT de verschillende fora in een sessie zou cachen, deze hangen immers niet af van de gebruiker!) Hiervoor kan je beter 1 file aanmaken, en daar de array in opslaan.
Het grote nadeel bij het cachen op niveau van de server (in '1' file dus) blijft het locken: wat als de cache geupdate wordt (dus er wordt geschreven naar de file), maar tegelijkertijd zijn er gebruikers die de file willen uitlezen => incorrecte data! Hiermee moet je rekening houden en eventueel een mechanisme bedenken waarbij het tegelijk schrijven en lezen niet kan voorkomen (suggesties zijn welkom, zelf heb ik nog niets denderend kunnen bedenken). Bij het cachen op niveau van de gebruiker (sessies) heb je dat probleem niet.
Conclusie: probeer het uit, benchmark het, en denk na hoe je gaat cachen (files <-> sessies). Maar zorg er vooral voor dat je eerst je queries zo optimaal mogelijk maakt: cachen is mooi meegenomen, meer niet!
PS: bij het gebruik van MySQL verlies je vooral veel tijd in het connecten naar de database: mysql_connect(). Zet maar even mysql_
pconnect() ipv. mysql_connect() in de for-lus, dan gaat het veel sneller. Dit maakt wel niets uit voor gewone scripts, daar connect je meestal toch maar 1 keer naar de server, en kan je dus de connectie-pointer niet opnieuw opvragen ipv. een nieuwe aan te vragen.
Is hier eigenlijk iemand met ervaring ivm. caching in files/sessies/Smarty/..? Ik ben er namelijk ook aan het denken om het te gaan gebruiken in een volgend project. Maakt GOT eigenlijk gebruik van caching?
[
Voor 19% gewijzigd door
Verwijderd op 16-09-2003 21:19
]