[PHP] Cachen van Queries (vreemde manier?)

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Maxonic
  • Registratie: September 2000
  • Laatst online: 05-09 22:23
Ik ben met een projectje bezig waarbij er bij het laden van een pagina best veel queries op de MySQL-database worden losgelaten.
Per user die ingelogd is, zijn deze queries voor een groot gedeelte hetzelfde.
Pagina 2 heeft bijvoorbeeld ongeveer 50% identieke queries aan pagina 1.
Nu zat ik eraan te denken om het resultaat van iedere query op te slaan in een sessie en deze vervolgens een naam te geven die bestaat uit de MD5 sleutel van de query zelf. Als ik de volgende keer een query uitvoer dan kijk ik eerst of er al een sessie bestaat met de MD5 sleutel van deze query.
Op zich heb ik deze manier van cachen nog niet eerder gezien en ik vraag me dan ook af of het wel effectief is.

Iemand ervaringen die hij/zij met mij wilt delen?

[ Voor 3% gewijzigd door Maxonic op 16-09-2003 13:00 ]


Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
Zoek eens op dingen in sessies opslaan, reden dat je dit niet veel ziet ( nooit??? ) is dat sessies serverruimte / server geheugenruimte in beslag nemen. Dit heeft als nadeel dat je niet te veel gebruikers kan dienen door je caching

Acties:
  • 0 Henk 'm!

  • mocean
  • Registratie: November 2000
  • Laatst online: 04-09 10:34
Als je overgaat op een template engine, kan je bijvoorbeeld ook complete pagina's cachen.

Zie bijvoorbeel Smarty

Koop of verkoop je webshop: ecquisition.com


Acties:
  • 0 Henk 'm!

  • Maxonic
  • Registratie: September 2000
  • Laatst online: 05-09 22:23
Laat zeggen dat je 100 users hebt over 5 minuten tijd.
De sessie geef je een lifetime van 5 minuten mee.
Elke user heeft zo'n 10kb aan queries gecached.
Dan valt die ene MB toch ook niet op in de gigantische temp directory die de meeste hosting providers hebben?

Acties:
  • 0 Henk 'm!

  • Kwai_gon_jinn
  • Registratie: Januari 2001
  • Niet online

Kwai_gon_jinn

[-geen icon-]

Je kunt zoals eerder genoemd Smarty gebruiken om pagina's te cachen.. of anders haal je zoveel mogelijk data uit de database om je pagina op te bouwen en stop dat ergens in een var/array m.b.v. serialize() (OOP?)

Confucius said: "In ancient time, learning was for self. Nowadays learning is for others."


Acties:
  • 0 Henk 'm!

Verwijderd

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.

Acties:
  • 0 Henk 'm!

Verwijderd

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 ]


Acties:
  • 0 Henk 'm!

  • slm
  • Registratie: Januari 2003
  • Laatst online: 12-11-2023

slm

Caching werkt beduidend sneller dan iedere keer een query aanroepen. Ik heb geen ervaring met Smarty maar ik heb voor enkele sites (die vrij veel bezoek trekken) wel gebruik gemaakt van caching naar files. Zeker als de resultaten niet iedere minuut wijzigen is het uitermate geschikt.

Hoeveel sneller het is heb ik nooit met een routine zoals hierboven berekend, maar zeker met slome MySQL servers (Vuurwerk) wil dat gecombineerd met veel bezoek wel een zeer groot verschil uitmaken. Wat ik doe is een file aanmaken met markup, dus geen CSV of XML file. Mijn enige doel is snelheid en dan heeft XML niet bijzonder veel toegevoegde waarde.

Wat ik doe is een php file includen die óf het ".html" bestand aanmaakt (en dus de db queried), óf deze file uitleest als hij al bestaat en aan de datum eisen voldoet. Bij locks krijg je een foutmelding die je kan ondervangen en kan je alsnog een query naar de de database sturen. Bij de eerstvolgende oproep dat het bestand niet in gebruik is, zal hij de ".html" file verversen.

Een hele simpele vorm van caching dus, maar werkt wel.

To study and not think is a waste. To think and not study is dangerous.


Acties:
  • 0 Henk 'm!

Verwijderd

Ja, een heel simpele vorm. Waarom ingewikkeld maken? :)

Maar hoezo ben jij zo zeker dat je altijd een fout krijgt (ivm. locking). Jij bedoelt dus dat je ook een fout krijgt als 1 gebruiker de .html aan het verversen is, en een andere de .html aan het uitlezen is (hij bestaat + datum eisen)? Kan je dan niet evengoed een 'halve' .html krijgen, zonder error?

Jij cachet dus hele paginas ipv. alleen resultaten van queries maar? (ik besluit dat omdat je opslaat onder .html files)? In dat geval zou ik ook eens kijken naar Smarty (http://smarty.php.net), doet ongeveer hetzelfde wat jij doet!

Acties:
  • 0 Henk 'm!

Verwijderd

Kijk anders ook eens naar AdoDB

Acties:
  • 0 Henk 'm!

Verwijderd

Caching van ADODB vind ik ondermaats: deze cachtet op basis van de MD5 van je query. Allemaal leuk en wel, maar je kan niet 1 specifieke cache wissen. Als je 1 cache resultaat wilt wissen, moet je ze ALLEMAAL wissen!

Ze zouden beter maken dat je eigen ID-string kan meegeven aan de ExecuteCache() functie, ipv. dat deze functie automatisch die MD5 ID genereert en dat je dus ahv. dat ID eventueel caches kan opheffen.

Acties:
  • 0 Henk 'm!

  • slm
  • Registratie: Januari 2003
  • Laatst online: 12-11-2023

slm

Verwijderd schreef op 16 September 2003 @ 23:03:
Ja, een heel simpele vorm. Waarom ingewikkeld maken? :)
Misschien vinden sommige mensen het leuk om dingen (evt onnodig) ingewikkeld te maken :)
Maar hoezo ben jij zo zeker dat je altijd een fout krijgt (ivm. locking). Jij bedoelt dus dat je ook een fout krijgt als 1 gebruiker de .html aan het verversen is, en een andere de .html aan het uitlezen is (hij bestaat + datum eisen)? Kan je dan niet evengoed een 'halve' .html krijgen, zonder error?
Dat weet ik helemaal niet zeker. De error check is er ingezet om geen php meldingen in de site te krijgen als de file niet bestaat, of te voorkomen dat de file zero length is. Je zou het write en locking mechanisme van php moeten onderzoeken om zeker te weten dat je een foutmelding krijgt. Ik heb er dan ook bijgezegd dat met name geschikt is als de data niet om de minuut wijzigd. Misschien ook wanneer het vaker wijzigt, maar dat zou je dan moeten nagaan. Je zou eventueel wel een soort van EOF markering kunnen aanbrengen in het weggeschreven bestand, maar daar ben je weer een extra check mee kwijt.
Jij cachet dus hele paginas ipv. alleen resultaten van queries maar? (ik besluit dat omdat je opslaat onder .html files)? In dat geval zou ik ook eens kijken naar Smarty (http://smarty.php.net), doet ongeveer hetzelfde wat jij doet!
Ik bedoel delen van pagina's in HTML code, dus bv een poll uitslag waarbij de HTML file wordt bijgewerkt zodra er weer gestemd is.

Ik zal ook eens kijken wat Smarty inhoud.

To study and not think is a waste. To think and not study is dangerous.


Acties:
  • 0 Henk 'm!

Verwijderd

Die EOF marking is een goede tip, daar ga ik eens over nadenken of dat geen problemen meer oplevert! :)

Ah oké, je cachet dus (delen van) pagina's. Ik ben voornamelijk geïnteresseerd in het cachen van resultaten van queries/arrays, en niet zo zeer in het HTML gedeelte ervan.

Smarty is in de eerste plaats een template engine: zorgt ervoor dat je je verwerking van je gegevens (database queries vooral) en de weergave ervan (html/css vooral) kan scheiden, wat betere en meestal efficiëntere code geeft! Daarnaast ondersteunt Smarty knappe features, waaronder caching van paginas er 1tje is :)

PS: misschien dwalen we wat af, ik hoop dat de topicstarter het nog genoeg ontopic en interessant vindt voor zijn probleem/vraag :)

[ Voor 11% gewijzigd door Verwijderd op 16-09-2003 23:47 ]


  • Maxonic
  • Registratie: September 2000
  • Laatst online: 05-09 22:23
Ow jawel hoor... :)
In ieder geval, het is me duidelijk geworden dat het te proberen valt maar dat ik eerst eens wat aandacht mag schenken aan query-optimalisatie.
Ik heb in mijn hoofd al een leuk systeempje zitten dat ervoor zorgt dat zelfs met caching, de bezoeker toch altijd up to datum resultaten krijgt.
echter wat DiEana al zij. Elke gebruiker maak wel weer een eigen sessie aan. Is dit echt niet anders mogelijk? Ik kan me nl. voorstellen dat er meerdere gebruikers zijn die hetzelfde resultaat moeten krijgen. Als ze dan de gegevens uit dezelfde sessie gebruikn zou dat natuurlijkw el lekker efficient zijn.

Verwijderd

Maxonic schreef op 17 September 2003 @ 00:07:
Ow jawel hoor... :)
In ieder geval, het is me duidelijk geworden dat het te proberen valt maar dat ik eerst eens wat aandacht mag schenken aan query-optimalisatie.
Inderdaad, doe dat eerst!
Ik heb in mijn hoofd al een leuk systeempje zitten dat ervoor zorgt dat zelfs met caching, de bezoeker toch altijd up to datum resultaten krijgt.
Leg het misschien eens uit, zodat wij je beter kunnen helpen? (en misschien zelf ideëen opdoen!)
echter wat DiEana al zij. Elke gebruiker maak wel weer een eigen sessie aan. Is dit echt niet anders mogelijk? Ik kan me nl. voorstellen dat er meerdere gebruikers zijn die hetzelfde resultaat moeten krijgen. Als ze dan de gegevens uit dezelfde sessie gebruikn zou dat natuurlijkw el lekker efficient zijn.
Je moet zien: als het 'kan' voorkomen dat 2 gebruikers dezelfde data zullen cachen, maar het komt niet altijd (!) voor, dan zijn sessies perfect te doen imho. Echter als het altijd (!) zo is dat 2 gebruikers voor een bepaalde query dezelfde resultaten zullen krijgen, zou ik niet sessies gebruiken, maar bijv. files. Echter kan je je eigen session handler functie maken, waarmee je misschien een systeem kan uitvinden zodat een gebruiker aan iemand anders zijn session kan als deze toch dezelfde data bevat dan de gebruiker in kwestie: http://be.php.net/manual/...sion-set-save-handler.php. Dat wordt wel moeilijk, denk ik :)

  • Grijze Vos
  • Registratie: December 2002
  • Laatst online: 28-02 22:17
Heeft MySQL nog geen caching ondersteuningen? En zitten die er anders niet aan te komen in hun nieuwste telg? ijkt me dat een db best wel wat ram mag gappen om de laatste queries en/of veelgebruikte queries incluis resultaat te bewaren, kan altijd handig zijn.

Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info


Verwijderd

Ik dacht dat de nieuwste versie van MySQL caching ondersteunt, maar het is op dit moment verrevan optimaal, denk ik.

  • slm
  • Registratie: Januari 2003
  • Laatst online: 12-11-2023

slm

MySQL 4 ondersteunt query cache. Hoe optimaal dit functioneert is mede afhankelijk van de verschillende queries die je er op loslaat:

SELECT * FROM mydb is niet hetzelfde als SELECT * From mydb zoals volgens mij ook in de manual staat. Het is dus zaak consequent je queries op te bouwen.

Daarnaast is het afhankelijk van hoeveel verschillende subsites gebruik maken van dezelfde MySQL server (als je bv geen dedicated server hebt) en hoe deze caching is ingesteld. Bij een gemiddelde provider kan je er denk ik wel vanuit gaan dat querychacing via files een stuk sneller is dan te vertrouwen op de ingebouwde query cache.

Het opslaan van query results voor elke user apart lijkt me niet direct verstandig, tenzij de queries per gebruiker verschillen én deze queries een zgn filesort (=erg traag) nodig hebben én bepaalde queries meerdere keren door dezelfde gebruiker op dezelfde manier worden aangeroepen.

To study and not think is a waste. To think and not study is dangerous.

Pagina: 1