Yii Performance Optimierung: Abfragen reduzieren

6. Oktober 2013 · Kategorien: PHP, Webentwicklung

Schnelle Performance

Erfahrungsgemäß sammeln sich unter Anderem im Yii Framework im Laufe der Zeit in größeren Projekten identische Datenbankabfragen an, die pro Request mehrfach ausgeführt werden. Das kann die Performance beeinflussen, da jedes Mal die Datenbank, zum Beispiel MySQL neu angefragt werden muss.

Oft kann man das vermeiden, indem man Relations richtig setzt und diese bei Bedarf sofort mitlädt. Auch sollte der Query-Cache aktiviert sein.

Wie kann ich die Yii Performance nun erhöhen?

Folgende Möglichkeit gibt es, um die Yii Performance zu optimieren, ohne die Datenbank überhaupt ein zweites Mal anzusprechen.

Nehmen wir an, wir möchten den eingeloggten Benutzer auslesen. Das kann in etwa so aussehen:

$user = User::model()->findById($id);

Yii würde nun eine SQL-Query bauen, die so aussehen kann:
SELECT * FROM users WHERE users.id = $id

Möchten wir an derer Stelle erneut den Benutzer auslesen, würde Yii erneut die Datenbank mit der gleichen Query abfragen.

Um das zu vermeiden, erzeugen wir in unserem /components-Ordner eine neue Klasse mit dem Namen MemorizableActiveRecord.php mit folgendem Aufbau:

MemorizableActiveRecord extends CActiveRecord
{
	protected $memorize = true;
	protected $memorizations = array();

	public function memorize($activate = true)
	{
		$this->memorize = $activate ? true : false;
		return $this;
	}

	protected function query($criteria,$all=false)
	{
		$memorizationKey = $this->modelName.md5(serialize($criteria)).'_'.($all ? '1' : '0');
		if($this->memorize)
		{
 			if(isset(static::$memorizationResults[$memorizationKey]))
			{
				return static::$memorizationResults[$memorizationKey];
			}
		}

		$result = parent::query($criteria, $all);

		if($this->memorize)
		{
			static::$memorizationResults[$memorizationKey] = $result;
		}

		return $result;
	}
}

Models, deren Datenbankabfragen nun nicht wiederholt werden sollen, müssen nun von MemorizableActiveRecord erben. Wir ändern also im Beispiel die erste Zeile in der User.php in:

class User extends MemorizableActiveRecord // statt: class User extends ActiveRecord

Was hat sich nun geändert?

Yii erstellt in jeder Methode eines ActiveRecords, die Daten ausliest, eine Criteria und ruft mit dieser die Methode query() auf. Diese Methode haben wir nun überschrieben, sodass sie erst in $memorizations nachschaut, ob bereits ein vorher die gleiche Datenbankquery durchgeführt wurde und damit bereits das Ergebnis bekannt ist. Wenn ja, wird das Ergebnis direkt aus dem Array zurückgegeben, was die Yii Performance positiv beeinflusst. Ansonsten wird die Datenbank befragt und das Ergebnis wird in $memorizations gespeichert.

Was gibt es zu beachten?

Wenn zu erwarten ist, dass das Ergebnis zwischen den Abfragen geändert wurde, sollte die Memorization deaktiviert werden. Ansonsten würde ja wieder das alte Ergebnis zurückgeliefert werden. Das geht, indem man die Methode memorize(false) aufruft:

$user = User::model()->findByPk(5);
echo $user->id; // = 5
$user->id = 6;
$user->save();

$user2 = User::model()->findByPk(5);
echo $user->id; // = 5 !!

$user3 = User::model()->memorize(false)->findByPk(5);
echo $user->id; // = 6

Diese Möglichkeit ist sicherlich auch in anderen Frameworks anwendbar, aber sollte – mit Bedacht eingesetzt – die Yii Performance erhöhen.

Autor: | Kategorien: PHP, Webentwicklung

1 Kommentar zu Yii Performance Optimierung: Abfragen reduzieren

  1. Ortreum sagt:

    Benutze besser md5(json_encode(…)) statt md5(serialize(…)). Das sollte noch etwas mehr Speed bringen.

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *