Я запускаю грабли для копирования некоторых живых данных в демонстрационных целях. Одна часть занимает очень много времени, чтобы бежать. Модели выглядят примерно так:
class Host
has_many :event_attendees, inverse_of: :host, dependent: :destroy
has_many :events, -> { distinct }, through: :event_attendees
end
class Attendee
has_many :event_attendees, inverse_of: :attendee, dependent: :destroy
has_many :events, through: :event_attendees
end
class Event
has_many :event_attendees, inverse_of: :event, dependent: :destroy
has_many :attendees, through: :event_attendees
end
class EventAttendee
belongs_to :event, inverse_of: :event_attendees, dependent: :destroy
belongs_to :attendee, inverse_of: :event_attendees, dependent: :destroy
belongs_to :host, inverse_of: :event_attendees, dependent: :destroy
end
Я копирую Хостов, Посетителей и События, отслеживая их идентификаторы (для копирования существующих EventAttendees). Кажется, все работает нормально.
def copy_events
log("Copying events...")
@event_ids_h = {}
ActiveRecord::Base.transaction do
Event.
where(organization_id: source_org_id).
distinct.
find_in_batches do |events|
fake_events = events.map do |event|
atts = event.attributes.except('id').merge(
...atts
)
Event.new(atts)
end
Event.import(
fake_events,
validate: true,
timestamps: false,
)
@event_ids_h = @event_ids_h.merge(Hash[events.map(&:id).zip(fake_events.map(&:id))])
end
end
end
Следующая часть работает ... но она требует forevvvvver. Около 2,5 часов около 600 000 записей.
def copy_event_attendees
log("Copying event attendee data...")
arr = EventAttendee.
where(attendee_id: @attendee_ids_h.keys, event_id: @event_ids_h.keys, host_id: @host_ids_h.keys).
pluck(:attendee_id, :event_id, :host_id).
map{ |ids| build_event_attendee_row(ids) }
unless arr.empty?
values_s = Arel::Nodes::ValuesList.new(arr).to_sql
ActiveRecord::Base.connection.insert(<<~SQL)
INSERT INTO event_attendees (attendee_id, event_id, host_id, created_at) #{values_s}
SQL
end
end
def build_event_attendee_row(ids)
ids[0] = @attendee_ids_h[ids.first]
ids[1] = @event_ids_h[ids.second]
ids[2] = @host_ids_h[ids.third]
ids.push(Time.current)
end
Я догадываюсь , что это WHERE IN
так долго. Но я не уверен, и я действительно хотел бы найти способ оптимизировать это, если это возможно.