Пакетная вставка в рельсы 3
Я хочу сделать пакетную вставку из нескольких тысяч записей в базу данных (POSTGRES в моем случае) из моего приложения Rails.
Каким будет "Rails" для этого?
Что-то быстрое, а также правильный способ сделать это.
Я знаю, что могу создать sql-запрос путем конкатенации строк, но мне нужен лучший подход.
Ответы
Ответ 1
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
Ответ 2
Наконец, я получил решение после двух ответов @Симоне Карлетти и @Sumit Munot.
Пока драйвер postgres не поддерживает массовую вставку метода ActiveRecord.create, я хотел бы пойти с activerecord-import gem. Он делает объемную вставку, и это тоже в одном заявлении вставки.
books = []
10.times do |i|
books << Book.new(:name => "book #{i}")
end
Book.import books
В POSTGRES это приводит к созданию одной статистики stat.
Как только драйвер postgres поддерживает массовую вставку метода ActiveRecord.create в одном заявлении insert, тогда решение @Simone Carletti имеет больше смысла:)
Ответ 3
Вы можете создать script в своей модели рельсов, написать свои запросы, чтобы вставить в это script
В рельсах вы можете запустить script с помощью
rails runner MyModelName.my_method_name
Это лучший способ, который я использовал в своем проекте.
Update:
Я использую следующее в своем проекте, но он не подходит для 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)
Ответ 4
Вы можете сделать это быстрым способом или способом Rails;) Самый лучший способ в моем опыте импортировать массивные данные в Postgres - через CSV. Что займет несколько минут, путь Rails займет несколько секунд, используя встроенную возможность импорта CSV Postgres.
http://www.postgresql.org/docs/9.2/static/sql-copy.html
Он даже запускает триггеры базы данных и уважает ограничения базы данных.
Изменить (после вашего комментария):
Попался. В этом случае вы правильно описали свои два варианта. Раньше я был в той же ситуации, реализовал его, используя Rails 1000 save! потому что это была самая простая вещь, которая работала, а затем оптимизировала ее для стратегии "добавить огромную строку запроса", поскольку она была на порядок лучше.
Конечно, преждевременная оптимизация - это корень всего зла, поэтому, возможно, сделать это простым медленным способом Rails и знать, что построение большой строки запроса является совершенно законным методом оптимизации за счет поддержания работоспособности. Я чувствую, что ваш реальный вопрос: "Есть ли способ Railsy, который не включает 1000 запросов?" - К сожалению, ответ на этот вопрос - нет.