Deutschland United States United Kingdom
ContentLion - Open Source CMS

QA UserCounter

Hab mal den aktuellen Stand hochgeladen.
Kannst du's nochmal testen? :)

Irgendwie verstehe ich deine Änderung nicht. Du nimmst die tracker_id aus den Primary Key, lässt das mit dem Date und dem Timestamp aber so wie vorher?

BTW: Mach mal den Default-Wert bei timestamp_first_visit raus. 0000-00-00 ist nicht wirklcih schön, da besser NULL zulassen.

Was auch noch nicht passt ist das Encoding der Tabelle. Nutze da am besten utf8 (hab ich an einigen stellen falsch gemacht in ContentLion damals)

http://code.contentlion.de/diff.php?repn…php&rev=7&peg=7

Versteh ich nicht. :rolleyes:
Ich hab den Timestamp zu nem Date umgewandelt, sodass nur jeden Tag ein neuer Eintrag angelegt wird.

In der activate.php ist die 1. Zeile mit dem DataBase::Current()->Execute(...) auskommentiert, hast du das vllt. übersehen? :huh:

EDIT:
Hatte es übersehen.^^
kA, wieso die Tracker-ID aus dem Primary Key draußen war, habs wieder rein gemacht.

@Encoding:
Hab ich auch gleich behoben, könntest du mal drüberschauen, ob das so stimmt? :)

Hab grad nochmal rein geschaut.
Hast zum Teil altes (berechtigtes) Feedback noch nicht umgesetzt:

QA UserCounter

Die Indizies und das mit dem ON DUPLICATE KEY.
Das Problem ist halt, dass du vielleicht mit ein paar 100 Einträgen getestet hast. Was passiert aber, wenn die Tabelle auf 10 Millionen Datensätze angestiegen ist? Sowas ist keine Seltenheit, vor allem, wenn du eine Gruppierung drin hast (wobe 100.000 vermutlich auch schon reichen). Da wird dir das Ding von der Performance her um die Ohren fliegen.

Das Problem sind die SELECTS beim INSERT. Die solltest du komplett herausnehmen, weil die bei vielen Einträgen Sau viel Ladezeit benötigen. Gleiches kannst du mit dem ON DUPLICATE KEY machen.

Und für die Auswertung solltest du noch passende MySQL Indizies setzen. Tust du das nicht, muss MySQL beim Auslesen jeden Datensatz vergleichen, durch einen passenden Index kann er fast direkt zum passenden Datensatz gehen. Schaus dir mal an.

Auch sehr langsam wird das mit dem Like sein. Würde das mit dem admin komplett rausnehmen, macht eigentlich keinen Sinn, wenn dann dürften gar keine Einträge von dir selbst getrackt werden (kannst du vielleicht über nen Cookie machen, den du dir selbst setzen kannst)

Die Funktion countVisitors ist leider ein noch extremeres Beispiel. Du liest alle Datensätze aus (Speicher wird komplett in die Brüche gehen) und zählst dann mit PHP. Warum zählst du nicht direkt über die COUNT-Funktion von MySQL?

Generier dir mal einfach eine Millionen Datensätze per Random in die Tabellen und teste, wie es dann läuft.

http://code.contentlion.de/filedetails.p…unter.php&rev=6

Hab grad nochmal rein geschaut.
Hast zum Teil altes (berechtigtes) Feedback noch nicht umgesetzt:

QA UserCounter

Die Indizies und das mit dem ON DUPLICATE KEY.
Das Problem ist halt, dass du vielleicht mit ein paar 100 Einträgen getestet hast. Was passiert aber, wenn die Tabelle auf 10 Millionen Datensätze angestiegen ist? Sowas ist keine Seltenheit, vor allem, wenn du eine Gruppierung drin hast (wobe 100.000 vermutlich auch schon reichen). Da wird dir das Ding von der Performance her um die Ohren fliegen.

Ehrlich gesagt habe ich gerade keine Idee, wie ich die Indizies nun gestalten soll... :S
Also das lediglich tracker_id nen privater Key wäre? --> Dann würde nicht jeden Tag ein Eintrag für den jeweiligen User angelegt. Hat aber auch zur Folge, das man nicht auswerten kann, wann der selbe User schon mal die Seite besucht hat.
Ansonsten wäre ein Beispiel sehr nett... ;)


Das Problem sind die SELECTS beim INSERT. Die solltest du komplett herausnehmen, weil die bei vielen Einträgen Sau viel Ladezeit benötigen. Gleiches kannst du mit dem ON DUPLICATE KEY machen.

Ja, stimmt.
Hatte bei den vielen Beiträgen einfach nicht mehr durchgesehen.^^


Und für die Auswertung solltest du noch passende MySQL Indizies setzen. Tust du das nicht, muss MySQL beim Auslesen jeden Datensatz vergleichen, durch einen passenden Index kann er fast direkt zum passenden Datensatz gehen. Schaus dir mal an.

Hmmm, da ist was Wahres dran!
Aber welchen? Primary Key? Was würdest du vorschlagen? :)


Auch sehr langsam wird das mit dem Like sein. Würde das mit dem admin komplett rausnehmen, macht eigentlich keinen Sinn, wenn dann dürften gar keine Einträge von dir selbst getrackt werden (kannst du vielleicht über nen Cookie machen, den du dir selbst setzen kannst)

Den kann ich eig. sogar ganz rausnehmen, da die Admin-Seiten dank dem folgendem Code in der update()-Methode gar nicht mit aufgenommen werden:

PHP-Quelltext

1
if (strpos($page,"admin")!==false) return 0;//Admin-Seiten nicht mit aufnehmen

Schneller gehts bestimmt nicht! :D


Die Funktion countVisitors ist leider ein noch extremeres Beispiel. Du liest alle Datensätze aus (Speicher wird komplett in die Brüche gehen) und zählst dann mit PHP. Warum zählst du nicht direkt über die COUNT-Funktion von MySQL?

Richtig, hatte ich vergessen, habs auch gleich mit umgesetzt. ;)


Generier dir mal einfach eine Millionen Datensätze per Random in die Tabellen und teste, wie es dann läuft.

http://code.contentlion.de/filedetails.p…unter.php&rev=6


Antworten stehen oben. ;)

Noch ne kleine Frage:
Wie lang kann die Tracker-ID max. werden? Würde nämlich gerne die Spalte "tracker_id" auf VARCHAR(50) kürzen... ;)

Habs herausgefunden: 32 Zeichen. :D

Genau, 32 Zeichen klingt gut.

Den Primary-Key brauchst du nicht als Index setzen, dass ist bereits einer ;-)

Beim Index musst du die Spalten aufnehmen, die du in den WHERE-Bedingungen der Selects nimmst. Da würde z.B. ein Index auf date Sinn machen. Indizies können aber auch über mehrere Spalten gehen.

Ok, schau ich mir nochmal an. ;)
Passt der Rest? :)

Das mit den countVisits halt noch.

Die Methode?:

PHP-Quelltext

1
2
3
4
5
6
7
8
9
10
11
    /*
     *
     * Count the visitors
     * @return int $visitors 
    */
    public function countVisitors () {
        
        $visitors DataBase::Current()->ReadField("SELECT COUNT(*) AS `visitors` FROM `{'dbprefix'}plugin_usercounter`; ");
        return $visitors;
        
    }


Da hab ich das doch schon gemacht, oder?^^

Wie müsste der Query dann aussehen?
So?:

MySQL-Abfrage(n)

1
2
3
4
5
6
7
DataBase::Current()->Execute("CREATE TABLE IF NOT EXISTS `{'dbprefix'}plugin_usercounter` (
  `tracker_id` varchar(50) NOT NULL,
  `date` date NOT NULL,
  `impressions` int(10) NOT NULL DEFAULT '1',
  `timestamp_first_visit` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`tracker_id`, `date`), INDEX (`date`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8;");

beim ersten kannste das ReadField direkt ins RETURN machen, dann sparst dir die Zuweisung.

Das mit dem INDEX sieht gut aus. Hab extra für dich heute nochmal nen Artikel dazu geschrieben. Schau dir mal den Absatz mit EXPLAIN zum Testen an:

http://blog.stevieswebsite.de/2013/08/ar…nbank-indizies/

Vielen vielen Dank! :thumbsup: :)
Du kannst dir gar nicht vorstellen, wie mir das weitergeholfen hat! :)

So, hab mal die / den Index(e) angepasst und eingecheckt. ;)

Alles klar, wird morgen getestet: http://www.contentlion.de/entwickler/aktuelle-tests.html

Hab jetzt mal vor öfter Posts der Art zu schreiben, wenn mir mal in nem Plugin oder so etwas auffällt. Dann hab ich nen Link, den ich dann später darunter posten kann ;-)

Sieht jetzt schon viel Besser aus mit dem Index ;-)

Ein Flüchtigskeitsfehler: Du hast die Tabelle fest contentlion_plugin_usercounter genannt, da fehlt die Prefix.

Und das LIKE mit dem Admin ist noch drin. Auf die Tabelle kannste am besten noch einen Index auf date und requests anlegen. Im Idealfall bauste die Funktion so, dass man auch die Anzahl übergeben kann, wie viele Zeilen man haben möchte (vielleicht auch mit Offset). Aber das ist nur wenn dir langweilig ist ;-)

Bei der Fukntion countPagesLoadToday haste nochmal sowas mit alles selektieren und in PHP zählen drin. Das kannste am besten auch wieder mit COUNT machen.



Dann können wir bald dein Plugin als Performantestes hier bezeichnen ;-)

Sieht jetzt schon viel Besser aus mit dem Index ;-)

Ja, find ich auch. :)


Ein Flüchtigskeitsfehler: Du hast die Tabelle fest contentlion_plugin_usercounter genannt, da fehlt die Prefix.

Ups! :rolleyes: Das hab ich natürlich gleich mal korrigiert! ;)


Und das LIKE mit dem Admin ist noch drin. Auf die Tabelle kannste am besten noch einen Index auf date und requests anlegen. Im Idealfall bauste die Funktion so, dass man auch die Anzahl übergeben kann, wie viele Zeilen man haben möchte (vielleicht auch mit Offset). Aber das ist nur wenn dir langweilig ist ;-)

Hatte ich vergessen. ^^
@INDEX: Habs gleich eingebaut. ;)

@Offset:
Ja. ^^
Hab ich das so richtig eingebaut? :rolleyes: :)


Bei der Fukntion countPagesLoadToday haste nochmal sowas mit alles selektieren und in PHP zählen drin. Das kannste am besten auch wieder mit COUNT machen.

Hmmm... Stimmt!
Wie bau ich denn da ein Count ein?
Muss ja die Impressions und nicht nur die Einträge zählen... :S
Hier mal der Code:

PHP-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
    public function countPagesLoadToday () {

        $db_erg DataBase::Current()->ReadRows("SELECT * FROM `{'dbprefix'}plugin_usercounter` WHERE `date` >= current_date(); ");
        $pages 0;

        foreach ($db_erg as $row) {
            $pages $pages $row->impressions;
        }

        return $pages;

    }



Dann können wir bald dein Plugin als Performantestes hier bezeichnen ;-)

Ja. :thumbsup: ^^

Stimmt, da musste SUM(impressions) nehmen.