Caching mit Objektabhängigkeit

Ich suche nach einer Möglichkeit Bereiche in Abhängigkeit von Objekten zu Cachen.

Beispielsweise habe ich eine Liste von Personen mit dazugehörigen Adressen.

Diese soll so lange gecached werden, bis sich entweder eine Person oder eine Adresse ändert.

D.h. ich würde das Caching dieser Liste gerne an die Objekte Person und Adresse "binden".

Wird nun beim Person oder Adresse die save oder delete-Funktion ausgeführt, sollte überprüft werden, ob gecachte Elemente existieren und diese zurückgesetzt werden.

Wie kann man so etwas umsetzen, oder gibt es andere Wege eine entsprechende Liste zu cachen?

Leider habe ich auf meinem Server keine APC-Unterstützung und die Applikation ist wirklich reichlich langsam…

Ich bin für jede Hilfe dankbar.

Hi und willkommen,

Yiis Caching-Implementierung unterstützt bereits Abhängigkeiten. Im Guide gibts dazu einen Abschnitt. Selbst hab ich das zwar auch noch nicht probiert, aber das Thema interessiert mich auch.

Zunächst müsstest du aber m.E. mal 2 Punkte klären:

  1. Was genau macht deine App so langsam? Hier kannst du z.B. mit der CProfileLogRoute analysieren, wo die Zeit genau bleibt. Evtl. ist der Aufbau der Liste gar nicht dein Problem.

  2. Irgendeinen Cache-Mechanismus brauchst du natürlich, um zu Cachen. Wenn APC nicht verfügbar ist wäre evtl. CDbCache eine Alternative.

Danke für die Antwort.

Als Cache nutze ich aktuell CFileCache, bin hier aber für Optimierungsvorschläge jederzeit offen

Das Mitgeben von Dependencies beim Caching hab ich mir schon mal angeschaut, aber nichts in meine Richtung gefunden

Ok, wiegesagt: Bevor du eine Cachestrategie entwickelst, solltest du erst die langsamen Teile deines Codes ausfindig machen. Ist es wirklich das Rendern einer Tabelle im View? Oder ist die Datenabfrage der Flaschenhals? Ich tippe mal eher auf letzteres. Dann würde sich Datencaching mit Abhängigkeit anbieten.

Eine Möglichkeit wäre z.B. CDbCacheDependency mit einer Bedingung wie z.B. SELECT MAX(updatedateum) FROM Person. updatedatum sei dabei die Spalte, in der du speicherst, wann ein Eintrag zuletzt geändert wurde. MAX(updatedatum) liefert also den Zeitpunkt, wann das letzte mal ein Eintrag in der Tabelle geändert wurde.

Die Daten im Cache bleiben mit dieser Abhängigkeit so lange gültig, solange dieser Zeitpunkt sich nicht ändert - ergo: solange kein Eintrag in der Tabelle geändert wurde.

Naja, wie gesagt Dependencies hab ich mir auch schon angeschaut, aber es geht eben nicht nur drum, wenn sich in einer Tabelle ein Eintrag ändert, sondern soll teilweise wie im Beispiel beschrieben auch mit mehreren Tabellen möglich sein + delete

Übrigens liegt der langsame Aufbau nicht an der Datenbank.

Ich habe die Applikation 1x lokal bei mir am Rechner und 1x auf einem Strato-Server.

Lokal funktioniert sie relativ schnell, auf dem Server dauert der Seitenaufbau ewig

Ok, die Änderung in beiden Tabellen müsstest du mit einem solchen Statement erfassen können:

SELECT MAX(p.updatedateum), MAX(a.updatedatum) FROM (Person p, Adresse a)

Bleibt noch das Delete-Problem. Erstes Ansatz der mir dazu einfällt: Die gecachten Daten bei jedem Löschvorgang entfernen. Gefällt mir aber auch noch nicht wirklich.

hmm, was auf diese Weise definitiv nicht abzufangen ist, ist das insert, das aber natürlich auch eine Rolle spielt, da sich ja das Listing auch beim Eintrag eines neuen Objektes ändert.

Die einzige Stelle, an der dieses aufschlägt ist meiner Meinung nach die Objekt-save Methode, daher ja auch mein Ansatz aus dem ersten Posting

Doch, genau dazu wird ja MAX(updatedatum) verwendet. Bei einem Insert hat der neu eingefügte Datensatz das "höchste" updatedatum (sofern du das beim Anlegen/Speichern eines neuen Datensatzes mit setzt). MAX(updatedatum) verändert also seinen Wert, die Cachedaten werden ungültig.

Ich hab mir jetzt noch mal ein paar Gedanken gemacht.

Bis auf die delete-Geschichte wäre es ja so grösstenteils abzubilden, wobei man teilweise reichlich viele Statements bauen müsste, wenn eine zu cachende Seite Daten vieler Objekte enthält.

Gibt es denn die Möglichkeit die keys aller gecachten Elemente einzusehen?

So dass ich bei der Vergabe eines keys die dargestellten Objektnamen einbaue und beim Saven / Deleten eines Objektes alle Caching-Einträge lösche, die im key den Objektnamen haben.

Bspw.


Yii::app()->cache->set('person_adress_list', $value);

und dann beim Update:




foreach ($cacheElements as $curElement) {

  $tokens = explode('_',$curElement);

  // oder per regex

  foreach ($tokens as $curToken) {

    if ($curToken == [OBJECTNAME]) {

      // delete $curElement

    }

  }

}



Hatte deine Antwort übersehen. :)

Hast du denn jetzt schon mal mit der CProfileLogRoute + Yii::beginProfile(‘blockID’) etwas rumgespielt? Wäre ja blöd, wenn du so viel Zeit in eine Cachestrategie investierst, wenn das Problem am Ende ganz wo anders liegt. Daher unbedingt erst mal sorgfältig analysieren, wo die Probleme herkommen.

So, nu hab ich mal alles durchforstet, hab aber keine pregnanten Stellen gefunden, die die Applikation auf dem Server langsamer machen.

Alle Abfragen sind etwas langsamer, entsprechend werd ich mir die Datenbank wohl mal zu Gemüte führen dürfen.

Vielleicht gibt es ja auch Probleme mit MySQL- und PHP-Version.

Allerdings bin ich bei meinem Versuch des Cachings weitergekommen.

Mein aktueller Stand:




    public function filters()

    {

        // echo Yii::app()->getGlobalState('cache_' . $this->getId());

        return array(

            'accessControl', // perform access control for CRUD operations

             array('COutputCache + list + show',

                    'varyByParam'=>array('page','id','s'),

                    'duration'=>Yii::app()->params['caching']['file'],

                    'dependency'=>array(

                         'class'=>'CGlobalStateCacheDependency',

                         'stateName'=>'cache_' . $this->getId(),

                    ),)

        );

    }



Und im ARObject in beforeSave()




Yii::app()->setGlobalState('cache_' . $this->_tableName(),time());



Allerdings habe ich jetzt das Problem, dass der Cache NICHT gelöscht wird wenn ich ein Objekt abspeichere.

Wenn ich allerdings das echo in der Filter-Methode schreibe, funktioniert das Reset des Caches wie gewünscht.

Weiß jemand warum???