Cachen von Daten

Beim Datencaching weden PHP-Variablen im Cache gespeichert bzw. von dort ausgelesen. Die wichtigsten beiden Methoden dafür sind in der Basisklasse CCache definiert: set() und get().

Eine Variable kann unter einer eindeutigen ID mit set() im Cache gespeichert werden:

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

Die gecachten Daten verbleiben für immer im Cache, außer sie werden aufgrund bestimmter Cacherichtlinien entfernt (z.B. wenn der Cachespeicher voll ist und alte Daten daher entfernt werden). Über einen weiteren Parameter kann dieses Verhalten geändert werden, so dass die Daten nach einer bestimmten Zeitspanne verfallen:

// Daten für max. 30 Sekunden um Cache halten
Yii::app()->cache->set($id, $value, 30);

Mit get() kann man später (im gleichen oder einem späteren Request) über die ID die Daten wieder aus dem Cache auslesen. Wird hier false zurückgegeben, ist der Wert nicht im Cache verfügbar. Evtl. sollte man ihn dann neu anlegen:

$value=Yii::app()->cache->get($id);
if($value===false)
{
    // $value neu generieren und für spätere Zwecke im Cache 
    // speichern, da der Wert nicht im Cache gefunden wurde
    // Yii::app()->cache->set($id,$value);
}

Es ist zu beachten, dass jede gespeicherte Variable eine eindeutige ID erhält. Allerdings muss diese ID NICHT zwischen verschiedenen Anwendungen auf dem selben Server eindeutig sein. Die Cachekomponente kann die IDs unterschiedlicher Anwendungen unterscheiden.

Einige Cachespeicher, wie MemCache oder APC, unterstützen die Abfrage mehrerer gespeicherter Werte auf einmal. Durch Verwendung von mget() kann so der Overhead beim Abrufen von gecachten Daten reduziert werden. Wird dieses Feature nicht vom Cachespeicher unterstützt, wird es von mget() simuliert.

Mit delete() wird ein einzelner Cacheeintrag gelöscht. Mit flush() kann der Cache komplett geleert werden. Beim Aufruf von flush() sollten Sie jedoch vorsichtig sein, da diesmal dabei auch alle gecachten Daten von anderen Anwendungen entfernt werden.

Tipp: Da CCache das Interface ArrayAccess implementiert, kann eine Cache-Komponente wie ein Array verwendet werden. Hier einige Beispiele:

$cache=Yii::app()->cache;
$cache['var1']=$value1;  // äquivalent zu: $cache->set('var1',$value1);
$value2=$cache['var2'];  // äquivalent zu: $value2=$cache->get('var2');

1. Cachen mit Abhängigkeit

Außer über die Verfallszeit kann die Gültigkeit eines Cacheeintrags auch von anderen Bedingungen abhängig sein. Cacht man zum Beispiel den Inhalt einer Datei, sollten die Cachedaten ungültig bzw. aktualisiert werden, sobald die Datei geändert wird.

Eine solche Abhängigkeit (engl.: dependency) wird durch eine Instanz vom Typ CCacheDependency oder deren Kindklasse repräsentiert. Beim Aufruf von set() kann ein solches Objekt zusammen mit den zu cachenden Daten übergeben werden.

// Der Wert verfällt in 30 Sekunden. Er kann auch schon eher verfallen
// wenn die abhängige Datei verändert wird
Yii::app()->cache->set($id, $value, 30, new CFileCacheDependency('DateiName'));

Wird $value mit get() ausgelesen, wird die Abhängigkeit ausgewertet. Falls es dort eine Änderung gab, wird false zurückgeliefert. In diesem Fall müssen die Daten neu generiert werden.

Folgende Cacheabhängigkeiten stehen bereit:

2. Cachen von Abfragen

Seit Version 1.1.7 kann Yii auch Abfragen cachen. Der Abfragecache basiert auf einem Datencache um die Ergebnisse einer Datenbankabfrage zu cachen. Dadurch kann später die Zeit zum Ausführen der Abfrage eingespart werden, weil das Ergebnis direkt aus dem Cache geliefert wird.

Info: Einige DBMS (z.B. MySQL haben einen solchen Abfragecache bereits serverseitig eingebaut. Unser Abfragecache ist allerdings flexibler und - zumindest potentiell - effizienter.

Aktivieren des Abfragecaches

Zum Aktivieren des Abfragecaches muss CDbConnection::queryCacheID auf die ID einer gültigen Cache-Komponente verweisen (Vorgabewert ist cache).

Verwendung des Abfragencaches mit DAO

Um den Abfragecache zu verwenden, ruft man die Methode CDbConnection::cache() auf, wenn eine DB-Abfrage durchgeführt wird:

$sql = 'SELECT * FROM tbl_post LIMIT 20';
$dependency = new CDbCacheDependency('SELECT MAX(update_time) FROM tbl_post');
$rows = Yii::app()->db->cache(1000, $dependency)->createCommand($sql)->queryAll();

Yii prüft hier zunächst, ob im Cache bereits ein noch gültiges Ergebnis für die SQL-Abfrage vorliegt. Dazu werden folgende drei Bedingungen sichergestellt:

  • dass sich im Cache ein Eintrag mit dem SQL-Ausdruck als Schlüssel befindet.
  • dass der Eintrag nicht verfallen ist (weniger als 1000 Sekunden seit dem Speichern im Cache vergangen sind)
  • dass die Abhängigkeit sich nicht verändert hat (der größte Wert für update_time ist immer noch der selbe wie beim Schreiben in den Cache).

Wenn alle diese Bedingungen erfüllt sind, wird das Abfrageergebnis direkt aus dem Cache geliefert. Andernfalls wird der SQL-Ausdruck an die Datenbank geschickt, das Ergebnis im Cache abgelegt und zurückgegeben.

Verwendung des Abfragecaches mit ActiveRecord

Man kann den Abfragecache auch mit Active Record verwenden. Dazu ruft man analog CActiveRecord::cache() wie folgt auf:

$dependency = new CDbCacheDependency('SELECT MAX(update_time) FROM tbl_post');
$posts = Post::model()->cache(1000, $dependency)->findAll();
// relational AR query
$posts = Post::model()->cache(1000, $dependency)->with('author')->findAll();

Die cache()-Methode ist in diesem Fall eine Abkürzung für CDbConnection::cache(). Intern versucht Yii beim Ausführen des SQL-Ausdrucks den Abfragecache wie im letzten Absatz beschrieben anzuwenden.

Cachen mehrfacher Abfragen

Normalerweise markiert ein Aufruf von cache (in CDbConnection oder CActiveRecord), dass die nächste SQL-Abfrage gecacht werden soll. Sämtlichen weiteren SQL-Abfragen werden NICHT gecacht, bis cache() erneut aufgerufen wird:

$sql = 'SELECT * FROM tbl_post LIMIT 20';
$dependency = new CDbCacheDependency('SELECT MAX(update_time) FROM tbl_post');
 
$rows = Yii::app()->db->cache(1000, $dependency)->createCommand($sql)->queryAll();
// Abfragencache wird NICHT verwendet:
$rows = Yii::app()->db->createCommand($sql)->queryAll();

Übergibt man an cache() den zusätzlichen Parameter $queryCount, kann man damit erzwingen, dass mehrere darauffolgende Abfragen gecacht werden. Im nächsten Beispiel wird cache() angewiesen, die nächsten zwei Abfragen zu cachen:

// ...
$rows = Yii::app()->db->cache(1000, $dependency, 2)->createCommand($sql)->queryAll();
// Abfragencache WIRD verwendet:
$rows = Yii::app()->db->createCommand($sql)->queryAll();

Wie bekannt kann es vorkommen, dass bei relationalen AR-Abfragen manchmal mehrere SQL-Abfragen ausgeführt werden (was man in den Logmeldungen kontrollieren kann). Der folgende Code führt zum Beispiel zu zwei Abfragen, sofern Beitrag und Kommentar mit HAS_MANY verknüpft sind:

  • Es holt sich zunächst die ersten 20 Beiträge
  • und dann die Kommentare für die erhaltenen Beiträge
$beitraege= Beitrag::model()->with('kommmentare')->findAll(array(
    'limit'=>20,
));

Verwendet man den Abfragencache wie folgt, wird lediglich die erste Abfrage gecacht:

$beitraege= Beitrag::model()->cache(1000, $dependency)->with('kommentare')->findAll(array(
    'limit'=>20,
));

Damit die Ergebnisse von beiden DB-Abfragen im Cache landen, muss die Anzahl der zu cachenden Abfragen über den zusätzlichen Parameter angegeben werden:

$beitraege= Beitrag::model()->cache(1000, $dependency, 2)->with('kommentare')->findAll(array(
    'limit'=>20,
));

Beschränkungen

Der Abfragecache funktioniert nicht mit Ergebnissen, die Ressource-Handles enthalten. Verwendet man z.B. den Spaltentyp BLOB, liefern einige DBMS ein Ressource-Handle als Daten zurück.

Einige Cache-Speicher begrenzen außerdem die Größe der ablegbaren Daten. Bei Memcache liegt diese Größe bei 1MB. Übersteigt ein Abfrageergebnis diese Größe, kann es nicht gecacht werden.

$Id: caching.data.txt 3125 2011-03-25 17:05:31Z qiang.xue $

Be the first person to leave a comment

Please to leave your comment.