it-swarm.com.ru

Пакетная вставка в Rails 3

Я хочу сделать пакетную вставку нескольких тысяч записей в базу данных (в моем случае это POSTGRES) из моего приложения Rails.

Каким был бы «путь Rails» для этого? Что-то быстрое и правильный способ сделать это.

Я знаю, что могу создать запрос SQL путем конкатенации атрибутов, но мне нужен лучший подход.

36
phoenixwizard

ActiveRecord .create метод поддерживает массовое создание. Метод эмулирует функцию, если БД не поддерживает ее, и использует базовый механизм БД, если функция поддерживается.

Просто передайте массив опций.

# Create an Array of new objects
User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }])

Блок поддерживается, и это общий способ для общих атрибутов.

# Creating an Array of new objects using a block, where the block is executed for each object:
User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) do |u|
  u.is_admin = false
end
55
Simone Carletti

Я наконец нашел решение после двух ответов @Simone Carletti и @Sumit Munot.

Пока драйвер postgres не поддерживает массовую вставку метода ActiveRecord .create, я бы хотел использовать activerecord-import gem . Это делает массовую вставку и это тоже в одном операторе вставки.

books = []
10.times do |i| 
    books << Book.new(:name => "book #{i}")
end
Book.import books

В POSTGRES это приводит к единственному состоянию вставки.

Как только драйвер postgres поддерживает массовую вставку метода ActiveRecord .create в один оператор вставки, тогда решение @Simone Carletti имеет больше смысла :)

20
phoenixwizard

Вы можете создать скрипт в своей модели Rails, написать свои запросы для вставки в этот скрипт В Rails вы можете запустить скрипт, используя

Rails runner MyModelName.my_method_name

Это лучший способ, который я использовал в своем проекте.

Обновление:

Я использую следующее в моем проекте, но это не подходит для sql инъекций . Если вы не используете пользовательский ввод в этом запросе, он может работать для вас

user_string = " ('[email protected]','a'), ('[email protected]','b')"
User.connection.insert("INSERT INTO users (email, name) VALUES"+user_string)

Для нескольких записей:  

new_records = [
  {:column => 'value', :column2 => 'value'}, 
  {:column => 'value', :column2 => 'value'}
]

MyModel.create(new_records)
2
Sumit Munot

Вы можете сделать это быстрым способом или способом Rails;) По моему опыту, лучший способ импортировать объемные данные в Postgres - через CSV. Что займет несколько минут, путь Rails займет несколько секунд, используя встроенную возможность импорта CSV в Postgres.

http://www.postgresql.org/docs/9.2/static/sql-copy.html

Он даже запускает триггеры базы данных и соблюдает ограничения базы данных.

Редактировать (после вашего комментария): В этом случае вы правильно описали свои два варианта. Я был в той же ситуации раньше, реализовал это с помощью Rails 1000 save! стратегия, потому что это была самая простая вещь, которая работала, а затем оптимизировала ее для стратегии «добавить огромную строку запроса», потому что она работала на порядок лучше.

Конечно, преждевременная оптимизация - корень всего зла, поэтому, возможно, сделайте это простым медленным способом Rails, и знайте, что создание большой строки запроса - это совершенно законный метод оптимизации за счет поддержания работоспособности. Я чувствую, что ваш реальный вопрос заключается в том, есть ли способ Railsy, ​​который не включает тысячи запросов? - к сожалению, ответ на этот вопрос - нет.

0
Chris Aitchison