Rails 3 отказывается загружать - PullRequest
0 голосов
/ 12 мая 2011

Я работаю в Rails 3.0.7.

У меня есть несколько ассоциаций "многие ко многим" и "один ко многим", которые не в состоянии увеличить нагрузку.

Мои ассоциации:

Person has_many :friends
Person has_many :locations through=> :location_histories
Location belongs_to :location_hour
Location_hour has_many :locations

В моем контроллере у меня есть следующее:

@people = Person.includes([[:locations=>:location_hour],:friends]).where("(location_histories.current = true) AND (people.name LIKE ? OR friends.first_name LIKE ? OR friends.last_name LIKE ? OR (friends.first_name LIKE ? AND friends.last_name LIKE ?))").limit(10).all

Тогда, на мой взгляд, у меня есть:

<% @people.each do |person| %>
  <tr>
    <td><%= link_to person.name, person %></td>
    <td><%= link_to person.friends.collect {|s| [s.full_name]}.join(", "), person.friends.first %></td>
    <td><%= link_to person.locations.current.first.name, person.locations.current.first %></td>
  </tr>
<% end %>

location.current - это область действия, определенная как:

scope :current, lambda {
  where("location_histories.current = ?", true)
}

Это работает, как ожидалось, и сначала генерирует 2 вызова базы данных: один для получения списка идентификаторов людей, а затем большой вызов базы данных, где все правильно объединено. ПРОБЛЕМА заключается в том, что после этого происходит n обращений к базе данных по направлениям:

SELECT 'friends'.* from 'friends' WHERE ('friends'.person_id = 12345)

Так для каждой итерации цикла в представлении. Излишне говорить, что это занимает некоторое время.

Я думал, что .всего вызовет нетерпеливую загрузку. У кого-нибудь есть идея, что здесь происходит?
Это тратит более 3 секунд на ActiveRecord. Слишком долго.

Буду очень признателен за любые предложения.

Спасибо.

Ответы [ 3 ]

1 голос
/ 12 мая 2011

OK. Наконец решено.
Мне нужно было позвонить как присоединяется, так и включает. Я также должен был удалить ассоциацию: location_current из объединения. Он создавал хаос, пытаясь

... LEFT OUTER JOIN `locations` ON `location_histories`.current = 1 ...  

Что, конечно, не является действительной ассоциацией. Похоже, что «текущее» предложение переносилось в JOINS.

Так что теперь у меня есть следующее, которое работает.

@people = Person.joins([[:locations=>:location_hour],:friends]).includes([[:locations=>:location_hour],:friends]).where("(location_histories.current = true) AND (people.name LIKE ? OR friends.first_name LIKE ? OR friends.last_name LIKE ? OR (friends.first_name LIKE ? AND friends.last_name LIKE ?))")

РЕЗЮМЕ:
1) Мне нужно было использовать оба соединения и включения для быстрой загрузки и правильной интерпретации условий. While ()
2) Мне нужно было сохранить связи с условиями (то есть: current_locations) вне предложения joins.

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

Обычно ли объединять объединения и включать?

Спасибо!

0 голосов
/ 05 июня 2012

Как ни странно, я получаю следующее поведение:

# fails to eager load tags--it only loads one of the tags for me, instead of all of them.
Product.find(:all, :conditions => ["products_tags.tag_id IN (?)", 2], :include => [:tags])

но это удается

Product.find(:all, :conditions => ["products_tags.tag_id IN (?)", 2], :include => [:tags], :joins => [:tags])

Это похоже на то, что запрос во внутренней таблице соединений как-то портит загрузку. Так что ваш ответ может быть правильным. Но здесь может быть что-то странное. (Рельсы 2.3.8 здесь).

0 голосов
/ 12 мая 2011

Я разобрался с ЧАСТЬЮ проблемы (хотя все еще есть непреднамеренное поведение). У меня было несколько областей, таких как location.current, как указано выше.

Я перенес эту логику в ассоциацию. Итак, в моей модели Person у меня теперь есть

has_many :current_locations, :source => :location, :through => :location_histories, :conditions => ["`location_histories`.current = ?", true]

И я звоню

Person.current_locations.first

вместо

Person.locations.current.first.  

Так что теперь инкрустация загружается как положено.

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

Я знаю это: когда я добавляю символы в предложение where, Rails выполняет внешнее соединение во время запроса (как объяснено здесь ), что и ожидается. Но почему это приводит к краху всего этого?

(Небольшая проблема здесь в том, что мне нужно сравнение строк. Чтобы получить правильное соединение, я вызываю .where как

.where(:table =>{:column=> 'string'})

, что эквивалентно

table.column = 'string'

в SQL, но мне нужно

table.column LIKE '%string%' 
...