Toon posts:

[php/mysql] Optimalisatie van stats script

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben bezig met het scripten van een statistieken script wat de bezoekers aantallen per dag bij houdt (unique, visitor, pageviews), de referer's bijhoudt en wat informatie van de bezoeker (os, browser, kleurdiepte, resolutie, ip) waar bij deze tabel structuur wordt gebruikt:

referer's
- id
- count
- url

info
- id
- os (tinyint)
- browser (tinyint)
- colordepth
- resolution
- ip

stats
- id
- visitors
- unique_visitors
- pageviews
- timestamp

En het script staat hier in een *.phps

Nu is mijn vraag, is dit efficiënt genoeg dus zodat het zo weinig mogelijk dataverkeer "verbruikt"? Want stats scripts zijn niet de scripts met de minste query's e.d. en om het Query gebruik een beetje omlaag te houden hebben ik een join gebruikt voor de nodige select's, maar misschien kan er nog meer "gejoint" worden (of andere dingen die beter kunnen)?

Alvast bedankt.

  • smaij
  • Registratie: November 2000
  • Laatst online: 11:26
Nu is mijn vraag, is dit efficiënt genoeg dus zodat het zo weinig mogelijk dataverkeer "verbruikt"?
Wat bedoel je daarmee. Het aantal queries heeft niks met je dataverkeer te maken.

voorderest werkte toenet je server niet maar nu wel zie ik.. lees ik zo effe door

edit:

Je kan ook gewoon alles inserten en updaten en later terugkijken wat een originele pagehit was.. zo heb je automatisch alle pageviews ook meegerekend.

kijk ook effe naar het opvragen van een ip adres.

gebruik beter dit kleine stukje

PHP:
1
2
3
4
5
    if (getenv("HTTP_X_FORWARDED_FOR")){
        $ip = getenv("HTTP_X_FORWARDED_FOR");
    }else {
        $ip = getenv("REMOTE_ADDR");
    }

[ Voor 0% gewijzigd door smaij op 14-10-2002 09:36 . Reden: toevoeging ]


Verwijderd

Topicstarter
Nou, hoe meer query's, hoe trager het script en hoe meer er geparsed moet worden (= meer dataverkeer?)

In ieder geval, ik wil het zo snel en efficiënt mogelijk houden.

Verwijderd

* Ik zou die if else constructie herschrijven met door een switch()
* $HTTP_SERVER_VARS heet tegenwoordig $_SERVER en $HTTP_COOKIE_VARS $_COOKIE

geen tijd om naar je queries te kijken...

  • smaij
  • Registratie: November 2000
  • Laatst online: 11:26
Verwijderd schreef op 14 oktober 2002 @ 09:36:
Nou, hoe meer query's, hoe trager het script en hoe meer er geparsed moet worden (= meer dataverkeer?)

In ieder geval, ik wil het zo snel en efficiënt mogelijk houden.
hoe meer er geparsed word, heeft niks te zeggen over het dataverkeer. hoe meer queries, zorgt er zeker voor dat het langzamer word. Je moet gewoon kijken wat toelaatbaar is. Heb je een dedicated server met 1 website erop, tja dan ziet dit er gewoon goed uit.

  • Eskimootje
  • Registratie: Maart 2002
  • Nu online
Kijk eens of je niet door een .php script een file kan scrhijven met de stats van de hele site dan kun je die zelf een keer per dag/week oid uitvoeren en dat scheelt je veel sql querie's.

  • smaij
  • Registratie: November 2000
  • Laatst online: 11:26
ik zie hier nog een rare query weet niet of het slim is of niet.

code:
1
SELECT COUNT(s.id), COUNT(r.id), COUNT(i.id) FROM stats AS s, referers AS r, info AS i WHERE s.timestamp='" . $timestamp . "' OR r.url='" . $user['referer'] . "' OR i.ip='" . $user['ip'] . "'


dit lijkt mij dat ie een tabel maakt van alle combinaties van die 3 tabellen bij elkaar en daarna doe je een where op die tabel, (zonder join)
kan iemand bevestigen dat dit eigenlijk langzamer is dan 3 kortere queries uit te voeren.. ik ben nog bezig in mijn boek van Connolly Begg

Verwijderd

Topicstarter
Dus wat "Nokia" zegt over het gebruik van switch() is eigenlijk niet nodig?

En ik heb trouwens dat IP stukje eerder gezien, ik zal het ff wijzigen, maar misschien is het ook wel handig om te weten waarom dat dan beter is :)

BTW: Mijn host heeft < Php 4.2, dus moet ik nog de oudere global vars gebruiken.

  • smaij
  • Registratie: November 2000
  • Laatst online: 11:26
Verwijderd schreef op 14 oktober 2002 @ 09:55:
Dus wat "Nokia" zegt over het gebruik van switch() is eigenlijk niet nodig?

En ik heb trouwens dat IP stukje eerder gezien, ik zal het ff wijzigen, maar misschien is het ook wel handig om te weten waarom dat dan beter is :)

BTW: Mijn host heeft < Php 4.2, dus moet ik nog de oudere global vars gebruiken.
http://www.php.net/search...tern=HTTP_X_FORWARDED_FOR

waarom zou je switch dan niet nodig hebben? :S

  • smaij
  • Registratie: November 2000
  • Laatst online: 11:26
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
function os() 
{ 
    global $HTTP_SERVER_VARS; 

    // int's 
    // 0: unknown; 1: windows 95; 2: windows Me; 3: windows 98; 4: windows XP; 5: windows 2000; 6: windows NT; 7: linux; 8: unix; 9: mac; 10: sun 
     
    if(eregi("(win|windows)[ ]*((nt)*[ /]*([0-9]+(.?[0-9]+))*)", $HTTP_SERVER_VARS['HTTP_USER_AGENT'], $regs)) 
    { 
        if(eregi("(win|windows)[ ](95)", $HTTP_SERVER_VARS['HTTP_USER_AGENT'])) 
        { 
            $os = 1; 
        } 
        else if(eregi("(win|windows)[ ](9x)[ ](4.90)", $HTTP_SERVER_VARS['HTTP_USER_AGENT'])) 
        { 
            $os = 2; 
        } 
        else if(eregi("(win|windows)[ ](98)", $HTTP_SERVER_VARS['HTTP_USER_AGENT'])) 
        { 
            $os = 3; 
        } 
        else if(eregi("(win|windows)[ ](NT)", $HTTP_SERVER_VARS['HTTP_USER_AGENT'])) 
        { 
            if(eregi("(win|windows)[ ](NT)[ ](5.1)", $HTTP_SERVER_VARS['HTTP_USER_AGENT'])) 
            { 
                $os = 4; 
            } 
            else if(eregi("(win|windows)[ ](NT)[ ](5.0)", $HTTP_SERVER_VARS['HTTP_USER_AGENT'])) 
            { 
                $os = 5; 
            } 
            else 
            { 
                $os = 6; 
            } 
        } 
        else 
        { 
            $os = 0; 
        } 
    } 
    else if(stristr($HTTP_SERVER_VARS['HTTP_USER_AGENT'], "Linux")) 
    { 
        $os = 7; 
    } 
    else if(stristr($HTTP_SERVER_VARS['HTTP_USER_AGENT'], "Unix")) 
    { 
        $os = 8; 
    } 
    else if(stristr($HTTP_SERVER_VARS['HTTP_USER_AGENT'], "Mac") || stristr($HTTP_SERVER_VARS['HTTP_USER_AGENT'], "PPC")) 
    { 
        $os = 9; 
    } 
    else if(stristr($HTTP_SERVER_VARS['HTTP_USER_AGENT'], "SunOS")) 
    { 
        $os = 10; 
    } 
    else 
    { 
        $os = 0; 
    } 

    return $os; 
}


dit kan toch een stukje korter als je switch gebruikt.. kijk eens op http://www.php.net/switch

edit:

sorry deed perongeluk quote ipv edit

[ Voor 0% gewijzigd door smaij op 14-10-2002 10:03 . Reden: foutje bedankt ]


  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Verwijderd schreef op 14 oktober 2002 @ 09:55:
BTW: Mijn host heeft < Php 4.2, dus moet ik nog de oudere global vars gebruiken.

Niet als ie php-4.1 of nieuwer gebruikt ;)

Wat ik persoonlijk zou doen is gewoon kijken hoe lang elk deel duurt.

Deze query snap ik niet:
PHP:
1
2
3
4
5
6
7
8
9
/* check if today is allready in table 'stats' */
$query[0] = mysql_query("SELECT COUNT(s.id), COUNT(r.id), COUNT(i.id) 
FROM stats AS s, referers AS r, info AS i 
WHERE s.timestamp='" . $timestamp . "' OR r.url='" . $user['referer'] . "' OR i.ip='" . $user['ip'] . "'")or die(mysql_error());
/* if not, add */
if(mysql_result($query[0], 0, 0) == "0")
{
    $query[1] = mysql_query("INSERT INTO stats (timestamp) VALUES ('" . $timestamp . "')")or die(mysql_error());
}

Je doet 3 counts en een zwik OR's om alleen te testen of de timestamp al gebruikt is :?
Kan dat niet gewoon met:
PHP:
1
2
3
4
5
6
7
8
9
/* check if today is allready in table 'stats' */
$query[0] = mysql_query("SELECT COUNT(*)
FROM stats
WHERE s.timestamp='" . $timestamp . '")or die(mysql_error());
/* if not, add */
if(mysql_result($query[0], 0, 0) == "0")
{
    $query[1] = mysql_query("INSERT INTO stats (timestamp) VALUES ('" . $timestamp . "')")or die(mysql_error());
} 

Verder lezend in je source zie ik dat dat niet echt handig gaat.
Let er echter op dat je een zgn "carthetisch product" doet en daardoor kan je _erg_ veel resultaten terug krijgen, zonder dat je daar wat aan hebt. De query zal daardoor iig niet echt vlot lopen, of in ieder geval heb je de kans dat ie erg sloom kan worden.

Verder doe je 4x een update oid op dezelfde tabel, als je die updates nou eens samenvoegd? Dus ipv direct de query runnen gewoon je "SET-deel" van je update-query bijwerken en dan aan het eind 1x een update doen die dus eventueel 4 velden tegelijk veranderd.

PHP:
1
2
3
4
5
6
7
8
9
10
11
        /* check if user is allready in table */
        if(mysql_result($query[0], 0, 2) == "0")
        {
            /* if not, add */
            $query[6] = mysql_query("INSERT INTO info (os, browser, color, resolution, ip) VALUES ('" . $user['os'] . "', '" . $user['browser'] . "', '" . $user['color'] . "', '" . $user['resolution'] . "', '" . $user['ip'] . "')")or die(mysql_error());
        }
        else
        {
            /* if so, update */
            $query[6] = mysql_query("UPDATE info SET os='" . $user['os'] . "', browser='" . $user['browser'] . "', color='" . $user['color'] . "', resolution='" . $user['resolution'] . "', ip='" . $user['ip'] . "'")or die(mysql_error());
        }

Ik mis een 'where' in die update :? :)

Magoed, al met al kan het allemaal nog wel iets efficienter, ik weet niet of al mijn tips toepasbaar of helemaal waar zijn, je zult het iig even goed na moeten kijken.

  • stekkel
  • Registratie: Augustus 2001
  • Laatst online: 12-07 11:54
[b][message=15554205,noline]smaij schreef op 14 oktober 2002 @ 09:59
dit kan toch een stukje korter als je switch gebruikt.. kijk eens op http://www.php.net/switch
switch is ook nog een sneller om dat de expressie waar naar gekeken wordt maar een keer geevalueerd hoeft te worden.
Bij een if elseif .... gebeurd dat bij ieder if / elsif statement.

Over snelheid gesproken, preg_match is sneller dan eregi.

[ Voor 0% gewijzigd door stekkel op 14-10-2002 10:10 . Reden: typo ]


Verwijderd

Topicstarter
Je doet 3 counts en een zwik OR's om alleen te testen of de timestamp al gebruikt is :?
In deze query probeer ik (met nadruk op "probeer") in 1x de nodige selects uit te voeren. En daarmee bedoel ik: Kijken of de bezoeker al met z'n IP, de datum van die dag en de referer al in de table staat. Kennelijk klopt er wejnig van deze join/query... iemand idee hoe ik dit anders kan doen? (ben nog vrij nieuw met joins)
Verder doe je 4x een update oid op dezelfde tabel, als je die updates nou eens samenvoegd? Dus ipv direct de query runnen gewoon je "SET-deel" van je update-query bijwerken en dan aan het eind 1x een update doen die dus eventueel 4 velden tegelijk veranderd.
Stom genoeg heb ik daar nog niet aan gedacht, gelijk ff veranderen dus :)
Ik mis een 'where' in die update :? :)
Klopt, kennelijk over het hoofd gezien omdat er nog maar 1 record in die table staat :)

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Verwijderd schreef op 14 oktober 2002 @ 16:30:
In deze query probeer ik (met nadruk op "probeer") in 1x de nodige selects uit te voeren. En daarmee bedoel ik: Kijken of de bezoeker al met z'n IP, de datum van die dag en de referer al in de table staat. Kennelijk klopt er wejnig van deze join/query... iemand idee hoe ik dit anders kan doen? (ben nog vrij nieuw met joins)

Als id een relatie tussen deze tabellen aangeeft kan het zo:
select ...
from stats
left join referers on stats.id = referers.id AND referer.url = $referer
left join info on stats.id = info.id AND info.ip = $ip

maar volgens mij ben je in dat geval een relatie aan het aanleggen die niet bestaat.
Ik denk dat je het best die counts los kan uitvoeren in 3 losse queries.

Verwijderd

Topicstarter
smaij schreef op 14 oktober 2002 @ 09:59:[...code...]

dit kan toch een stukje korter als je switch gebruikt.. kijk eens op http://www.php.net/switch
Dan is mijn vraag: Hoe wil je dat dan doen? Ik gebruik vrijwel nooit switch() en volgens mij (en volgens php.net als ik goed gelezen heb) kun je geen eregi erin uitvoeren, dus heeft het weinig zin?

Of je moet iets anders bedoelen.

  • PrinsEdje80
  • Registratie: Oktober 2001
  • Laatst online: 01-01 15:26

PrinsEdje80

Holographic, not grated...

Ik zou die switch zelfs laten vervallen en het als volgt doen:
PHP:
1
2
3
4
5
6
7
8
9
function browser() 
{ 
    if(eregi("(Konqueror)", $HTTP_SERVER_VARS['HTTP_USER_AGENT'])) 
      return 1;
    if(eregi("(Gecko)", $HTTP_SERVER_VARS['HTTP_USER_AGENT']) && !eregi("(Netscape)", $HTTP_SERVER_VARS['HTTP_USER_AGENT'])) 
      return 2;
    if(eregi("(Opera)", $HTTP_SERVER_VARS['HTTP_USER_AGENT'])) 
      return 3;
//etc

Dan gaat hij niet alle eregi's uitvoeren. Zodra hij bijv. Konquerer al heeft gevonden, floept hij uit de functie.

Dit kun je dus ook bij je OS scriptje doen.
Volgens mij is bovenstaande methode sneller dan een switch-statement...

Used to be Down Under... Foto gallery


  • stekkel
  • Registratie: Augustus 2001
  • Laatst online: 12-07 11:54
PrinsEdje80 schreef op 15 oktober 2002 @ 00:16:
Ik zou die switch zelfs laten vervallen en het als volgt doen:
PHP:
1
2
3
4
5
6
7
8
9
10
function browser() 
{ 
    if(eregi("(Konqueror)", $HTTP_SERVER_VARS['HTTP_USER_AGENT'])) 
      return 1;
    if(eregi("(Gecko)", $HTTP_SERVER_VARS['HTTP_USER_AGENT']) 
            && !eregi("(Netscape)", $HTTP_SERVER_VARS['HTTP_USER_AGENT'])) 
      return 2;
    if(eregi("(Opera)", $HTTP_SERVER_VARS['HTTP_USER_AGENT'])) 
      return 3;
//etc

Dan gaat hij niet alle eregi's uitvoeren. Zodra hij bijv. Konquerer al heeft gevonden, floept hij uit de functie.

Dit kun je dus ook bij je OS scriptje doen.
Volgens mij is bovenstaande methode sneller dan een switch-statement...
Een switch statement evalueerd de expressie slechts 1 keer. Dit betekend dat na evaluatie er direct naar de bijbehorende case gesprongen kan worden.

Waneer je het zelfde met if statements zou doen dan kan het in het ergste geval voorkomen dat bij de laatste elseif of else statement pas de wenselijke uitkomst heb.

Dus veel beter is nadenken hoe je 1 maal een preg_match kan uitvoeren en met de gevonden expressie de switch structure in gaat.

Dus in jouw geval moet je een regular expressie maken die de browser string eruit trekt die je vervolgens in een switch gebruikt.
Bij jouw huidige code wordt er namelijk in het ergste geval 3 x een eregi uitgevoerd. (Om nog maar niet te spreken over wanneer je 10 bekende browsers moet afhandelen)

Nog een ding: preg functies zijn sneller dan ereg functies!

  • PrinsEdje80
  • Registratie: Oktober 2001
  • Laatst online: 01-01 15:26

PrinsEdje80

Holographic, not grated...

stekkel schreef op 15 oktober 2002 @ 18:52:
[...]


Een switch statement evalueerd de expressie slechts 1 keer. Dit betekend dat na evaluatie er direct naar de bijbehorende case gesprongen kan worden.

Waneer je het zelfde met if statements zou doen dan kan het in het ergste geval voorkomen dat bij de laatste elseif of else statement pas de wenselijke uitkomst heb.

Dus veel beter is nadenken hoe je 1 maal een preg_match kan uitvoeren en met de gevonden expressie de switch structure in gaat.

Dus in jouw geval moet je een regular expressie maken die de browser string eruit trekt die je vervolgens in een switch gebruikt.
Bij jouw huidige code wordt er namelijk in het ergste geval 3 x een eregi uitgevoerd. (Om nog maar niet te spreken over wanneer je 10 bekende browsers moet afhandelen)

Nog een ding: preg functies zijn sneller dan ereg functies!
Dank voor de zeer heldere uitleg. _/-\o_
Van preg had ik idd begrepen dat dit sneller was.

offtopic:
Maar mijn oplossing is wel sneller dan die van hem toch }) O-)

Used to be Down Under... Foto gallery

Pagina: 1