Минимизация вызовов к базе данных в рельсах - PullRequest
2 голосов
/ 22 мая 2010

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

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

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

def newsfeed

  - find out which users i need
  - retrieve those users via DB

  - find out which events happened for these users
  - for each of those events
        - retrieve new set of users

  - find out which groups are relevant
  - for each of those groups
        - retrieve new set of users 

  - etc, etc 

end

Ответы [ 4 ]

2 голосов
/ 22 мая 2010

Денормализация - это магический пароль для вашей ситуации.

Есть несколько способов сделать это: Например, сохраните идентификаторы последних 10 пользователей в событии и группе.

Или создайте новую модель NewsFeedItem (belongs_to :parent, :polymorphic => true). Когда пользователь посещает событие, создайте элемент NewsFeedItem с денормализованной информацией, такой как имя пользователя, его фотография профиля и т. Д. Спасает вас от повторных запросов к user_events и пользователям.

1 голос
/ 23 мая 2010

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

У меня есть два предложения:

1) Вы переоцениваете свой алгоритм / дизайн на основе того, чего вы действительно хотите достичь. Например, в случаях, когда в приложении есть пользователи, у которых потенциально может быть много постов, и приложение хочет выполнить некоторый алгоритм на основе количества постов, тогда каждый раз будет достаточно дорого подсчитывать их посты. Чтобы оптимизировать это, в модель пользователя можно добавить столбец post_count и увеличивать это число всякий раз, когда пользователь успешно делает сообщение. Точно так же, если вы можете установить какую-то связь между вашим пользователем, событиями, группами и т. Д., Подумайте о чем-то в этих строках.

2) Если первое решение неосуществимо, то для чего-либо подобного вы должны избегать выполнения нескольких запросов, а затем использовать ruby ​​для обработки данных, что, очевидно, будет очень дорогим и никогда не рекомендуется, если у вас большой набор данных. Итак, вам нужно сделать один SQL-запрос, используя соединение, и получить все данные за один раз. Также выбирайте только те имена полей из базы данных, которые вам нужны. Это действительно помогает в случае больших наборов данных. Например, если вам нужен идентификатор пользователя и event_id из таблицы user и events и ничего больше, тогда сделайте что-то вроде этого

User.find(:all, 
      :select => 'users.id, users.event_id', 
      :joins => 'join events on users.id = events.user_id',
      :conditions => ['users.id in (your user ids)'])

Надеюсь, это укажет вам правильное направление.

1 голос
/ 22 мая 2010

Хотите ли вы показать все детали одновременно (я имею в виду, что при загрузке страницы вы действительно хотите загрузить всю эту информацию), Если не то, что вы можете сделать, это загрузить их по требованию

следующим образом

def новостная лента

  • узнать, какие пользователи мне нужны
  • получить этих пользователей через DB

  • выясните, какие события произошли для этих пользователей

    как только вы покажете события, дайте им кнопку или что-то еще для детализации (по запросу), затем загрузите их, используя AJAX (чтобы страница не обновлялась))

    используйте эту технику несколько раз, когда пользователи хотят углубляться в детали

Делая это, вы сэкономите много вычислительной мощности и получите только те детали, которые нужны пользователю

Я не знаю, применимо ли это к вашей ситуации

Если нет, то вам нужно найти более оптимизированный способ загрузки деталей

ура, sameera

1 голос
/ 22 мая 2010

Вы должны быть в состоянии сделать это с только одним запросом на цикл событий / групп .Что вы захотите сделать: внутри вашего цикла for добавьте идентификаторы пользователей в Set , затем после цикла for, получите все пользовательские записи с этими идентификаторами.Промыть и повторить.Вот пример:

def newsfeed

  user_ids = Set.new
  # find out which users i need
  ...  add ids to user_ids
  # retrieve those users via DB
  users = User.find(user_ids.to_a)

  # find out which events happened for these users
  # you might want to add a condition
  # that limits then events returned to only recent ones
  events = Event.find_by_user_id(user_ids.to_a)

  user_ids = Set.new
  events.each do |event|
    user_ids << discover_user_ids_for_event(event)

  # retrieve new set of users
  users = User.find(user_ids.to_a)

  # ... and so on  

end

Я не уверен, что ваш метод должен возвращать, но вы, вероятно, сможете выяснить, как использовать идею группировки finds вместе, работая сколлекции идентификаторов для минимизации запросов к БД.

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