J'ai une méthode dans les rails qui fait quelque chose comme ceci:
a = Foo.new("bar")
a.save
b = Foo.new("baz")
b.save
...
x = Foo.new("123", :parent_id => a.id)
x.save
...
z = Foo.new("zxy", :parent_id => b.id)
z.save
Le problème est que cela prend de plus en plus d'entités. Je soupçonne que c'est parce qu'il doit frapper la base de données pour chaque enregistrement. Puisqu'ils sont imbriqués, je sais que je ne peux pas sauver les enfants avant que les parents ne soient sauvés, mais j'aimerais sauver tous les parents à la fois, puis tous les enfants. Ce serait bien de faire quelque chose comme:
a = Foo.new("bar")
b = Foo.new("baz")
...
saveall(a,b,...)
x = Foo.new("123", :parent_id => a.id)
...
z = Foo.new("zxy", :parent_id => b.id)
saveall(x,...,z)
Cela ferait tout cela en seulement deux hits de base de données. Existe-t-il un moyen simple de le faire dans les rails, ou suis-je obligé de le faire un à la fois?
la source
ActiveRecord::Base.transaction { records.each(&:save) }
ou similaire, vous pouvez au moins mettre tous les INSERT ou UPDATE dans une seule transaction.Puisque vous devez effectuer plusieurs insertions, la base de données sera frappée plusieurs fois. Le retard dans votre cas est dû au fait que chaque sauvegarde est effectuée dans différentes transactions DB. Vous pouvez réduire la latence en regroupant toutes vos opérations dans une seule transaction.
Votre méthode de sauvegarde pourrait ressembler à ceci:
L'
save
appel sur l'objet parent enregistre les objets enfants.la source
insert_all (Rails 6+)
Rails 6
a introduit une nouvelle méthode insert_all , qui insère plusieurs enregistrements dans la base de données en une seuleSQL INSERT
instruction.En outre, cette méthode n'instancie aucun modèle et n'appelle pas les rappels ou validations Active Record.
Alors,
il est nettement plus efficace que
si tout ce que vous voulez faire est d'insérer de nouveaux enregistrements.
la source
L'une des deux réponses trouvées ailleurs: par Beerlington . Ces deux sont votre meilleur pari pour la performance
Je pense que votre meilleur pari en termes de performances sera d'utiliser SQL et d'insérer en masse plusieurs lignes par requête. Si vous pouvez créer une instruction INSERT qui fait quelque chose comme:
INSERT INTO foos_bars (foo_id, bar_id) VALUES (1,1), (1,2), (1,3) .... Vous devriez pouvoir insérer des milliers de lignes dans une seule requête. Je n'ai pas essayé votre méthode mass_habtm, mais il semble que vous pourriez faire quelque chose comme:
De plus, si vous recherchez Bar par "some_attribute", assurez-vous que ce champ est indexé dans votre base de données.
OU
Vous pouvez toujours jeter un œil à activerecord-import. Il est vrai que cela ne fonctionne pas sans modèle, mais vous pouvez créer un modèle uniquement pour l'importation.
À votre santé
la source
vous devez utiliser ce joyau "FastInserter" -> https://github.com/joinhandshake/fast_inserter
et l'insertion d'un grand nombre et de milliers d'enregistrements est rapide car ce joyau ignore l'enregistrement actif et n'utilise qu'une seule requête brute SQL
la source
Vous n'avez pas besoin d'un joyau pour frapper DB rapidement et une seule fois!
Jackrg l'a élaboré pour nous: https://gist.github.com/jackrg/76ade1724bd816292e4e
la source