Что самый быстрый путь состоит в том, чтобы создать массовые ассоциации HABTM в направляющих?

У меня есть две таблицы с отношениями HABTM в направляющих. Что-то как следующее:

class Foo < ActiveRecord::Base
  has_and_belongs_to_many :bars
end

class Bar < ActiveRecord::Base
  has_and_belongs_to_many :foos
end

Теперь у меня есть новое Foo объект, и хочет к массе - присваивают тысячи панелей ему, которые я предварительно загрузил:

@foo = Foo.create
@bars = Bar.find_all_by_some_attribute(:a)

Что самый быстрый путь состоит в том, чтобы сделать это? Я попробовал:

@foo.bars = @bars
@foo.bars << @bars

И оба выполненных действительно замедляются с записью как следующее для каждого bar:

Столбцы bars_foos (1,1 мс) ПОКАЗЫВАЮТ ПОЛЯ ОТ bars_foos SQL (0,6 мс) INSERT INTO bars_foos (bar_id, foo_id) ЗНАЧЕНИЯ (100, 117200)

Я посмотрел на расширения площади, но import функция, кажется, не работает без модели (Model.import), который устраняет его использование для объединяющей таблицы.

Я должен записать SQL, или направляющие имеют более симпатичный путь?

14
задан klochner 4 February 2010 в 21:37
поделиться

3 ответа

Я думаю, что лучше всего с точки зрения производительности использовать SQL и массовую вставку нескольких строк на запрос. Если вы можете создать оператор INSERT, который выполняет что-то вроде:

INSERT INTO foos_bars (foo_id,bar_id) VALUES (1,1),(1,2),(1,3)....

Вы должны иметь возможность вставлять тысячи строк в один запрос. Я не пробовал ваш метод mass_habtm, но похоже, что вы могли бы сделать что-то вроде:

bars = Bar.find_all_by_some_attribute(:a)
foo = Foo.create
values = bars.map {|bar| "(#{foo.id},#{bar.id})"}.join(",")
connection.execute("INSERT INTO foos_bars (foo_id, bar_id) VALUES #{values}")

Кроме того, если вы ищете Bar по "some_attribute", убедитесь, что это поле проиндексировано в вашей базе данных.

7
ответ дан 1 December 2019 в 15:01
поделиться

Это было быстрее, чем эквивалентный собственный код rails в 7 раз:

class << Foo
  def mass_habtm(attr_array)
    attr_str = attr_array.map{|a| %Q{'#{a}'} }.uniq.join(",")
    self.connection.execute(%Q{insert into foos_bars (foo_id,bar_id) 
                     select distinct foos.id,bars.id from foos,bars 
                     where foos.id = #{self.id} 
                     and bars.some_attribute in (#{attr_str})})
  end
end

Мне кажется, что это достаточно простая операция, и она должна поддерживаются эффективно в Rails, я хотел бы услышать, есть ли у кого-нибудь более чистый способ.

Я использую 2.2.2, может быть, это более эффективно реализовано в 3.x? и обнаружил то же самое в 3.0.2.

1
ответ дан 1 December 2019 в 15:01
поделиться

При использовании PHP не имеет значения, какой тип был у формы. Вы всегда получаете пары ключ/значение.

Поэтому, если более жесткое кодирование является единственной причиной отказа и вы используете PHP, просто используйте enctype = «multipart/form-data».

Есть ли другая причина?

-121--1264830-

Другим интересным решением для PHP 5,2 и выше является использование расширения фильтра: http://www.php.net/manual/en/book.filter.php

Это позволяет проверить и очистить пользовательские вводы. Имеется множество встроенных фильтров, которые можно комбинировать с флагами для изменения их поведения. Кроме того, эти фильтры могут также использоваться для проверки/очистки входов, поплавков, сообщений электронной почты и определенных регулярных выражений.

Я лично начал использовать их в своих проектах для проверки форм и вывода введенных пользователем данных, и я очень рад, что это сделал. Хотя, когда я вставляю значения в базу данных MySQL, я использую подготовленные запросы для дополнительной безопасности. Эти решения вместе помогут избежать большинства инъекций SQL и атак типа XSS.

-121--3853777-

Честно говоря, имеет _ и _ принадлежит _ ко _ многим - это очень устаревший способ делать вещи. Вы, вероятно, должны посмотреть на _ много: через , который является новым способом объединения таблиц, и уже довольно давно.

class Foo < ActiveRecord::Base
  has_many :foobars
  has_many :bars, :through => :foobars

  def add_many_bars(bars)
    bars.each do |bar|
      self.bars << bar
    end
  end
end

class Bar < ActiveRecord::Base
  has_many :foobars
  has_many :foos, :through => :foobars
end

class FooBar < ActiveRecord::Base
  belongs_to :foo
  belongs_to :bar
end

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

-4
ответ дан 1 December 2019 в 15:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: