Создание тысяч записей в Rails - PullRequest
3 голосов
/ 06 января 2011

Позвольте мне установить сцену: мое приложение имеет дело с подарочными картами.Когда мы создаем карты, у них должна быть уникальная строка, которую пользователь может использовать для ее погашения.Поэтому, когда кто-то заказывает наши подарочные карты, например, розничный продавец, нам нужно сделать много новых карточных объектов и сохранить их в БД.

Имея это в виду, я пытаюсь понять, насколько быстро я могумое приложение генерирует 100 000 карт.Я не эксперт по базам данных, поэтому мне нужен кто-то, чтобы объяснить этот маленький феномен: когда я создаю 1000 карт, это занимает 5 секунд.Когда я создаю 100 000 карт, это должно занять 500 секунд, верно?

Теперь я знаю, что вы хотите увидеть, метод создания карт, который я использую, потому что первое предположение будет, что он становится медленнее, потому что этопроверка уникальности связки карт, больше по мере продвижения.Но я могу показать вам мое задание по рейку

desc "Creates cards for a retailer"
task :order_cards, [:number_of_cards, :value, :retailer_name] => :environment do |t, args|
  t = Time.now
  puts "Searching for retailer"
  @retailer = Retailer.find_by_name(args[:retailer_name])
  puts "Retailer found"
  puts "Generating codes"
  value = args[:value].to_i
  number_of_cards = args[:number_of_cards].to_i
  codes = []
  top_off_codes(codes, number_of_cards)
  while codes != codes.uniq
    codes.uniq!
    top_off_codes(codes, number_of_cards)
  end
  stored_codes = Card.all.collect do |c|
    c.code
  end
  while codes != (codes - stored_codes)
    codes -= stored_codes
    top_off_codes(codes, number_of_cards)
  end
  puts "Codes are unique and generated"
  puts "Creating bundle"
  @bundle = @retailer.bundles.create!(:value => value)
  puts "Bundle created"
  puts "Creating cards"
  @bundle.transaction do
    codes.each do |code|
      @bundle.cards.create!(:code => code)
    end
  end
  puts "Cards generated in #{Time.now - t}s"
end

def top_off_codes(codes, intended_number)
  (intended_number - codes.size).times do
    codes << ReadableRandom.get(CODE_LENGTH)
  end
end

Я использую гем под названием readable_random для уникального кода.Поэтому, если вы прочитаете весь этот код, то увидите, что он выполняет все тесты на уникальность еще до того, как начнет создавать карты.Он также записывает обновления состояния на экран во время его работы, и он всегда некоторое время при создании.Между тем он пролетает через тесты на уникальность.Поэтому мой вопрос к сообществу stackoverflow: почему моя база данных замедляется, когда я добавляю больше карт?Почему это не линейная функция в отношении времени на карту?Я уверен, что ответ прост, и я просто придурок, который ничего не знает о хранении данных.И если у кого-то есть какие-либо предложения, как бы вы оптимизировали этот метод и как быстро, по вашему мнению, вы могли бы заставить его создать 100 000 карт?

(Когда я изобразил свое время на графике и сделал быструю кривую)в соответствии с формулой линии, я рассчитал, сколько времени потребуется для создания 100 000 карточек с моим текущим кодом, и он говорит о 5,5 часах. Это может быть совершенно неправильно, я не уверен. Но если оно останется на линии, которую я подгоняю,это было бы прямо там.)

Ответы [ 2 ]

2 голосов
/ 06 января 2011

Не ответ на ваш вопрос, но пара предложений о том, как сделать вставку быстрее:

  • Используйте Ruby's Hash для устранения дубликатов - используйте коды вашей карты в качестве ключей хеша, добавляя их в хеш, пока ваш хэш не достигнет желаемого размера. Вместо этого вы также можете использовать класс Set (но я сомневаюсь, что он быстрее, чем Hash).
  • Использовать массовую вставку в базу данных вместо серии запросов INSERT. Большинство СУБД предоставляют возможность: создать текстовый файл с новыми записями и указать базе данных для его импорта. Вот ссылки для MySQL и PostgreSQL .
1 голос
/ 06 января 2011

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

ЧтоБД вы используете?

Какие индексы имеются?

Любые оптимизации БД, например, кластеризованные таблицы / индексы.

Не уверен в поддержке транзакций Ruby - это @В строке bundle.transaction есть что-то из ActiveModel или другой используемой вами библиотеки?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...