2009-12-24 4 views
1

J'ai une base de données SQLite3, qui contient un grand nombre de données. J'utilise la migration pour cela.Les migrations de Ruby on Rails sont très lentes

3 tables auront suivant le nombre d'enregistrements: Table_1 aura environ 10 dossiers chaque enregistrement de Table_1 sera associé à ~ 100 enregistrements dans Table_2 chaque enregistrement de Table_2 sera associée à ~ 2000 enregistrements dans Table_3

Le nombre d'enregistrements sera d'environ 10 * 100 * 2000 = 2000000

Cela prend beaucoup de temps ... l'événement, si je remplir ma base de données avec environ 20 000 dossiers, il faut environ 10 minutes.

De plus, je constate que, lors de l'exécution de la migration, interpréteur Ruby prend seulement 5% de temps CPU et 95% reste inutilisé ...

la raison de cette performance pure?

Répondre

2

Tout simplement, en insérant de grandes quantités d'enregistrements à travers des objets AR manuellement sauver un à la fois va prendre des années. Le meilleur compromis entre la rapidité et la "propreté" (c'est-à-dire pas un hack dodgy complet) pour l'insertion de grandes quantités de données est la méthode d'importation des extensions d'ar (http://github.com/zdennis/ar-extensions). Ce n'est pas idéal, mais c'est mieux que n'importe laquelle des alternatives que je pourrais trouver, et la syntaxe est propre et ne nécessite pas que vous tombiez sur SQL brut (ou n'importe où à proximité).

Exemple de syntaxe:

items = Array.new 
1.upto(200) do |n| 
    items << Item.new :some_field => n 
end 
Item.import items, :validate => false 

Au moins dans mysql cette volonté batch les enregistrements dans une seule instruction INSERT avec plusieurs ensembles de valeurs. Assez vite.

1

Si vous exécutez chaque instruction INSERT dans sa propre transaction, SQLite peut être très, très lent. Mais si vous exécutez tout cela en une seule transaction (ou un ensemble logique de transactions), alors cela peut être très rapide.

+0

Pourriez-vous expliquer plus en détail - comment je peux vider toutes les données préparées en une seule transaction. J'utilise Ruby on Rails pour générer des données de manière aléatoire (à des fins de test). Je ne connais que la méthode ActiveRecord: Base.save(), mais, autant que je sache, elle doit être appelée pour chaque objet créé, mais pas pour le modèle entier ... ou? – AntonAL