Tengo un método en rieles que está haciendo algo como esto:
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
El problema es que esto toma más tiempo y más entidades agrego. Sospecho que esto se debe a que tiene que llegar a la base de datos para cada registro. Como están anidados, sé que no puedo salvar a los niños antes de que se salven los padres, pero me gustaría salvar a todos los padres a la vez y luego a todos los niños. Sería bueno hacer algo como:
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)
Eso lo haría todo en solo dos visitas a la base de datos. ¿Existe una manera fácil de hacer esto en rieles, o estoy atrapado haciéndolo uno a la vez?
fuente
ActiveRecord::Base.transaction { records.each(&:save) }
o similar puede al menos poner todos los INSERT o UPDATE en una sola transacción.Dado que necesita realizar múltiples inserciones, la base de datos se activará varias veces. El retraso en su caso se debe a que cada guardado se realiza en diferentes transacciones de base de datos. Puede reducir la latencia al incluir todas sus operaciones en una sola transacción.
class Foo belongs_to :parent, :class_name => "Foo" has_many :children, :class_name => "Foo", :foreign_key=> "parent_id" end
Su método de guardado podría verse así:
# build the parent and the children a = Foo.new(:name => "bar") a.children.build(:name => "123") b = Foo.new("baz") b.children.build(:name => "zxy") #save parents and their children in one transaction Foo.transaction do a.save! b.save! end
La
save
llamada al objeto principal guarda los objetos secundarios.fuente
insert_all (rieles 6+)
Rails 6
introdujo un nuevo método insert_all , que inserta varios registros en la base de datos en una solaSQL INSERT
declaración.Además, este método no crea una instancia de ningún modelo y no llama devoluciones de llamada o validaciones de Active Record.
Entonces,
Foo.insert_all([ { first_name: 'Jamie' }, { first_name: 'Jeremy' } ])
es significativamente más eficiente que
Foo.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }])
si todo lo que quiere hacer es insertar nuevos registros.
fuente
Una de las dos respuestas encontradas en otro lugar: por Beerlington . Esos dos son tu mejor apuesta para el rendimiento.
Creo que su mejor apuesta en cuanto al rendimiento será usar SQL e insertar de forma masiva varias filas por consulta. Si puede crear una declaración INSERT que haga algo como:
INSERT INTO foos_bars (foo_id, bar_id) VALUES (1,1), (1,2), (1,3) .... Debería poder insertar miles de filas en una sola consulta. No probé tu método mass_habtm, pero parece que podrías hacer algo como:
bars = Bar.find_all_by_some_attribute(:a) foo = Foo.create values = bars.map {|bar| "(#{foo.id},#{bar.id})"}.join(",") connection.execute("INSERT INTO foos_bars (foo_id, bar_id) VALUES #{values}")
Además, si está buscando en Bar por "algún_ atributo", asegúrese de tener ese campo indexado en su base de datos.
O
Es posible que todavía eche un vistazo a activerecord-import. Es cierto que no funciona sin un modelo, pero puede crear un modelo solo para la importación.
FooBar.import [:foo_id, :bar_id], [[1,2], [1,3]]
Salud
fuente
necesitas usar esta gema "FastInserter" -> https://github.com/joinhandshake/fast_inserter
e insertar una gran cantidad y miles de registros es rápido porque esta gema omite el registro activo y solo usa una sola consulta SQL sin procesar
fuente
¡No necesitas una gema para golpear DB rápido y solo una vez!
Jackrg nos lo ha solucionado: https://gist.github.com/jackrg/76ade1724bd816292e4e
fuente