Rails: Performancesteigerung durch Piggy Backing

Die Technik ist nicht neu, aber gestern beim Treffen der Ruby On Rails Usergroup Hamburg erntete ich einige komische Blicke, als ich in kleiner Runde vom „Piggy Backing“ erzählte, daher hier nochmal etwas genauer erklärt worum es geht.

Piggy Backing - so bescheuert der Name dieser Technik klingt (bedeutet eingedeutscht wohl so etwas wie Huckepack tragen), so gut erklärt er eigentlich genau das was damit gemacht wird - und von Stefan Kaes gibt es sogar eine Erweiterung von ActiveRecord dafür - so komisch kann es also nicht sein ;)

Konkret geht es darum, beim Laden von Objekten aus der Datenbank direkt ein paar Attribute anderer Objekte mitzuladen. Ich erkläre es mal am Beispiel von wevent, weil wir es dort kürzlich eingebaut haben und uns dadurch einiges an Performancezugewinn sichern.

Achtung, es folgen verkomplizierte Beschreibungen

Wir haben eine Tabelle mit den Events, zu denen auch die Modelle Stadt und Location gehören. Wenn wir die Events für die Darstellung in einer Liste laden, wollen wir dazu auch direkt die jeweilige Location und ihre Stadt ziehen - soweit nichts besonderes und in ActiveRecord einfach durch etwas wie folgendes zu lösen:

Dadurch werden die mit einem Event verknüpfte Location und Stadt direkt mitgeladen - in unserem Falle ist das so aber nicht wirklich ideal: Erstens wird Performance auf Datenbankseite verschenkt, da die kompletten Stadt- und Location-Objekte geladen werden (wir brauchen nur den Namen) und zweitens, weil diese Objekte nach dem Laden auch komplett von Ruby initialisiert werden müssen, was auf Interpreterseite Zeit kostet.

Was wir also brauchen ist die Möglichkeit, den venue_name und city_name als Attribute des Eventobjekts zu laden. Dafür müssen zwar auf Datenbankebene immer noch die Stadt- und Location-Tabellen gejoint werden, allerdings holen wir dieses Mal nur den Namen und nicht das ganze Objekt… außerdem müssen nach dem Laden keine Stadt- und Location-Instanzen erzeugt werden (die Namen sind ja Attribute des Eventobjekts). Wie funktioniert das?

Attached at the hip

In der Praxis läufts folgendermaßen: Die Abfrage muss angepasst werden, um die nötigen Tabellen zu joinen und die zusätzlichen Attribute zu laden:

Uff, sieht ja gar nicht mehr so schön Rails-like aus - stimmt! Wenn man sich dafür aber mal Stefan Kaes’ Performancevergleich in der Gegenüberstellung von Laden per :include und Piggy Backing ansieht, dann kann man diese Schönheitseinbußen durchaus in Erwägung ziehen.

Wer jetzt noch nicht abgeschreckt ist, der muss sein Modell noch etwas anpassen, um auf die zusätzlichen Attribute auch zugreifen zu können. In unserem Fall müsste das Eventmodell um zwei Methoden erweitert werden, welche den Zugriff auf dem Stadt- und Location-Namen regeln:

Was passiert da genau? Diese Methoden garantieren mir, dass ich bei einem Event auf jeden Fall an die Eigenschafft komme, die ich haben möchte: Ist beim Zugriff auf @event.venue_name das per Piggy Backing geladene Attribut venue_name vorhanden, wird dieses zurückgegeben, ohne einen Zugriff auf die Datenbank. Ist es nicht vorhanden (bspw. weil der Event an anderer Stelle ohne Piggy Backing geladen wurde), so wird die per Assoziation (Event belongs_to :venue) festgelegte Location aus der Datenbank geladen und ihr Name zurückgegeben.

Klingt theoretisch viel komplizierter als es praktisch ist und es macht teilweise echt Sinn, solche Probleme auf diese Art und Weise zu lösen.

iOS app for GitHub

iOctocat

ist GitHub für die Hosentasche - deine Projekte und das was dort passiert immer dabei mit deinem iPhone und iPod Touch.
Die App ist