Ограничение SQL-запросов, генерируемых Rails при доступе к данным из нескольких таблиц на одной странице - PullRequest
0 голосов
/ 22 февраля 2011

У меня есть много предметов и много пользователей в базе данных. Пользователь может установить статус для различных элементов. Три таблицы (они были упрощены в этом объяснении) - пользователи, статусы, элементы. Модели показаны ниже.

class Item < ActiveRecord::Base
    has_many :statuses  
end

class Status < ActiveRecord::Base
    belongs_to :user
    belongs_to :item    
end

class User < ActiveRecord::Base
    has_many :statuses  
end

Контроллер

class ItemController < ApplicationController
    def index
        @items = Item.all
    end
end

Представление (это было упрощено, в моем коде я фактически генерирую форму для статуса, чтобы пользователь мог создавать / изменять свой статус, но в приведенном ниже примере я просто делаю так, как будто статус распечатывается как текст):

<th>Item ID</th>
<th>Item Status</th>
...
<% @items.each do |item| %>
  <td><%= item.id %></td>
  <% status = item.statuses.where(:user_id => current_user.id) %>
  <td><%= status.first.status %></td>
<% end %>

Вот запросы, сгенерированные Rails:

Item Load (0.3ms)  SELECT `items`.* FROM `items` ORDER BY id asc
SQL (0.2ms)  SELECT COUNT(*) FROM `statuses` WHERE (`statuses`.item_id = 1) AND (`statuses`.`user_id` = 103)
SQL (0.2ms)  SELECT COUNT(*) FROM `statuses` WHERE (`statuses`.item_id = 2) AND (`statuses`.`user_id` = 103)
Status Load (0.1ms)  SELECT `statuses`.* FROM `statuses` WHERE (`statuses`.item_id = 2) AND (`statuses`.`user_id` = 103) LIMIT 1
SQL (0.2ms)  SELECT COUNT(*) FROM `statuses` WHERE (`statuses`.item_id = 3) AND (`statuses`.`user_id` = 103)

Все элементы выбираются в одном запросе SQL, что я считаю хорошим. Затем кажется, что выполняется запрос SELECT COUNT (*), если состояние найдено, то это состояние выбирается с помощью другого запроса SQL, это происходит для каждого элемента.

Предположение, что есть намного лучший способ сделать это, когда у меня есть несколько сотен элементов, количество выполняемых SQL-запросов огромно! Если у кого-нибудь есть какие-либо советы о том, как они поступят по этому поводу, мне было бы интересно услышать.

Спасибо.

1 Ответ

0 голосов
/ 28 марта 2011

Решение состоит в том, чтобы включать статусы при создании предметов.

@items = Item.includes(:statuses).all

А затем используйте метод select для возврата соответствующего статуса.

item.statuses.select {|s| s.user_id => current_user.id}

Магия рельсов иногда приводит к этим безумным запросам, поскольку item.statuses можно интерпретировать какмассив объектов состояния или ActiveRecord Relation.

Когда вы вызываете метод where для item.statuses, по умолчанию используется поведение Relation ActiveRecord и создается новый запрос SQL.Если вы вызываете select, item.statuses ведет себя как массив.

Это также относится и к таким методам, как sum.Очень раздражает!

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