2014-09-10 2 views
1

Если у меня есть следующая схема:Вставка вложенного объекта Эффективное

class Sinbad < ActiveRecord::Base 
    has_many :tinbads 
    accepts_nested_attributes_for: :tinbads 
end 

class Tinbad < ActiveRecord::Base 
    belongs_to :sinbad 
    has_many :pinbads 
    accepts_nested_attributes_for: :pinbads 
end 

class Pinbad < ActiveRecord::Base 
    belongs_to :tinbad 
end 

и это не редкость для Tinbad иметь несколько сотен Pinbads, является их общим способом создать вложенную Sinbad без вызова сотни запросов ?

Я пришел к грустному пониманию того, что активная запись не поддерживает пакетные вставки, но есть ли способ вокруг этого, который не включает в себя написанный вручную sql? Я посмотрел на https://github.com/zdennis/activerecord-import, но он не поддерживает вложенные объекты. В настоящее время в действии SinbadController#create действуют >400 операции вставки и это наиболее распространенное действие.

Вот пример того, что я хочу, чтобы не произошло: https://gist.github.com/adamkuipers/12578343d31a651bee4a

Вместо вставки в photos таблицы N раз, я хочу, чтобы вставить только один раз.

+0

Вы пытались использовать массив вложенных хэшей? я думаю, что он должен работать до тех пор, пока веб-сервер поддерживает этот объем данных, отправленных в почтовом запросе –

+0

@MohammadAbuShady, я не уверен, что понимаю. Я создаю только один «Sinbad» в контроллере, но активная запись генерирует отдельный «insert» для каждого вложенного атрибута и рекурсивно генерирует инструкцию insert для вложенных атрибутов этого атрибута. – adam2012

+0

хорошо не так логично, это разные таблицы –

ответ

0

У меня такая же проблема. Я разбор больших таблиц и схемы, используемых для хранения данных вложен, поэтому я вставив только один «Sinbad», но тысячи «Pinbad» может получить вставлены сразу ...

Что я придумал чтобы ускорить вставку, чтобы навалом вставить нижние листья схемы (визуализировать схему как дерево), так как это должна быть модель с наибольшим количеством экземпляров для создания - в вашем случае экземпляров Pinbad. Мы не можем вставлять средние листовые материалы, поскольку объемная вставка не позволяет извлекать идентификаторы вставленных множительных моделей (см. Обсуждение here относительно postgresql, например). Так что это не идеально, но это единственный способ сделать вставки более эффективными (без изменения самой схемы).

Вы должны удалить accepts_nested_attributes_for, как вам нужно, чтобы сохранить объекты на себя, и это удобно использовать activerecord-import для массовой вставки:

class Sinbad 
    # 
    # Let's imagine you still receive the params as if you were using accepts_nested_attributes, 
    # Meaning :pinbads_attributes will be nested under :tinbads_attributes 
    # that will be nested under :sinbad 
    # 
    def self.efficient_create params 
    # I think AR doesn't like when attributes doesn't exist, 
    # so we should keep the tinbads attributes somewhere else 
    tinbads_attributes = params[:tinbads_attributes] 
    params.delete :tinbads_attributes 
    sinbad = self.create! params 

    # Array that will contain the attributes of the pinbads to bulk insert 
    pinbads_to_save = [] 
    # ActiveRecords-Import needs to know which cols of Pinbad you insert 
    pinbads_cols = [:tinbad_id, :name, :other] 

    # We need to manually save the tinbads one by one, 
    # but that's what happen when using accepts_nested_attributes_for 
    tinbads_attributes.each do |attrs| 
     pinbads_attribute = attrs[:pinbads_attributes] 
     attrs.delete :pinbads_attibutes 
     tinbad = sinbad.tinbads.create! attrs 

     pinbads_attributes.each do |p_attrs| 
     # Take care to put the attributes 
     # in the same order than the pinbad_cols array 
     pinbads_to_save << [tinbad.id, p_attrs[:name], p_attrs[:other]] 
     end 
    end 

    # Now we can bulk insert the pinbads, using activerecord-import 
    Pinbad.import_without_validations_or_callbacks pinbad_cols, pinbads_to_save 
    end 
end 

Вот что я сделал в моей ситуации и как последний уровень в иерархии схемы имеет наибольшее количество экземпляров для создания, общее время вставки значительно сократилось. В вашем случае вы замените ~ 400 вставок Pinbad на 1 объемную вставку.

Надеюсь, что это поможет, и я открыт для любого предложения или альтернативного решения!

Смежные вопросы