post

Ruby on Rails | Massenverarbeitung mit ActiveRecord

Bei der produktiven Nutzung eines von mir entwickelten Tools hat es zugeschlagen: Es ist halt doch etwas anderes mit ein paar Testdatensätzen oder mit ein paar Hunderttausend Datensätzen zu arbeiten. Die Laufzeiten für INSERTs und UPDATEs gingen gar nicht. Also was tun? Das Projekt ist mit ActiveRecord realisiert.

Etwas Recherche hat gezeigt: Da geht einiges!

Abrufen von Datensätzen

Das Abrufen von Datensätzen via ActiveRecord kann über verschiedene Techniken beschleunigt werden. Erster Ansatzpunkt sind die Funktionen zum Abruf von Datensätzen in Bündeln (Batches). Hierzu bietet ActiveRecord bereits Funktionen an, so dass eine große Menge an Datensätzen nicht auf einmal, sondern stapelweise und somit schonend für Arbeitsspeicher und Swap Bereich verarbeitet werden kann (Retrieving Multiple Objects in Batches).

Generell sollte man die Menge an Datensätzen aus der Datenbank bereits bei der Abfrage weitestgehend reduzieren um im Programmcode möglichst nur noch mit den relevanten Datensätzen zu arbeiten. Es sollten also nicht die Ruby Methoden find bzw. find_all zum Filtern von Datensätzen genutzt werden, sondern besser bereits bei der Abfrage entsprechende Einschränkungen gemacht werden.

Also so eher nicht:

Besser:

Bei n:m Beziehungen sollte man mit der ‚through‘ Anweisung arbeiten um die Beziehungen zwischen Objekten darzustellen (Siehe http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association). ActiveRecord generiert dann SQL mit entsprechenden JOIN Anweisungen, anstatt über mehrere SELECTs die Anfragen zusammenzubauen.

UPDATEs auf vielen Datensätzen

Updates auf vielen Datensätzen ist ineffizient, wenn für jeden Datensatz ein eigenes UPDATE Statement generiert wird. Hier schafft update_all Abhilfe. Man selektiert vorab alle Datensätze die aktualisiert werden sollen und kann dann diese in einem Rutsch bearbeiten:

Somit wird ein UPDATE Statement für alle Datensätze erzeugt.

Massen-INSERT

Das massenhafte Anlegen neuer Datensätze frisst ebenso sehr viel Performance, da für jeden INSERT eine eigene Transaktion gestartet wird. Hier kann man manuell eingreifen und ActiveRecord beibringen alle INSERTs ein einer Transaktion zu verarbeiten:

Schreibe einen Kommentar

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