Могу ли я создать отношения Active Record на основе отсутствия совпадений - PullRequest
1 голос
/ 15 мая 2019

Я пытаюсь ускорить индексную страницу в приложении rails, у которого много n + 1 запросов.

На данный момент у меня есть метод, который в основном переворачивает отношения (находит записи, не связанные с текущей)

Class Person < ActiveRecord::Base
    has_many_and_belongs_to_many :bankholidays, join_table: “working_bankholidays”

    def free_bankholidays
        Bankholiday.where(“id NOT IN (?)” bankholiday_ids)
    end
end
Class Bankholiday < ActiveRecord::Base
    has_many_and_belongs_to_many :persons, join_table: “working_bankholidays”
end
Class WorkingBankholiday < ActiveRecord::Base
    belongs_to :person
    belongs_to :bankholiday
end

Метод free_bankholidays внутри Person возвращает любые Bankholidays, которые не связаны с текущим Person. Это работает нормально, но замедляет работу, если я загружаю страницу индекса несколькими людьми. Есть ли способ, которым я могу перенести это в отношения, чтобы они могли быть загружены?

1 Ответ

0 голосов
/ 15 мая 2019

Вам нужно выходное соединение и выберите результаты, в которых внешнее соединение создало NULL.

Вам понадобится SQL:

SELECT bankholidays.*
FROM bankholidays
  LEFT OUTER JOIN working_bankholidays on bankholidays.id = working_bankholidays.bankholiday_id
  AND working_bankholidays.person_id = 111
WHERE working_bankholidays.id is NULL

Проблема в том, что вынеобходимо условие для person_id в предложении FROM.Если он находится в предложении WHERE, вы получите другие результаты.

Когда он находится в предложении FROM, он будет использовать условие для обработки таблицы working_bankholidays, как если бы в ней были только строки ссоответствие person_id.Он делает это перед выполнением внешнего соединения, поэтому, если нет записей с совпадающим person_id, он добавит записи из внешнего соединения со значениями NULL во всех полях таблицы working_bankholidays.

К сожалению, я не знаю никакого способа сделать это с активными ассоциациями записи.Все активные ассоциации записей помещают условия в предложение WHERE, а не в предложение FROM.

Если вы измените has_many_and_belongs_to_many на «сквозные», и вы сделаете это:

class Person
  def free_bankholidays
    Bankholiday.left_joins(:working_bankholidays).where(working_bankholidays: {id: nil, person_id: self.id})
  end

это даст вам следующее:

SELECT bankholidays.*
FROM bankholidays
  JOIN working_bankholidays on bankholidays.id = working_bankholidays.bankholiday_id
WHERE working_bankholidays.id is NULL
  AND working_bankholidays.person_id = 111

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

РЕДАКТИРОВАТЬ:

См. Комментарий engineermnky.Я еще не пробовал, поэтому я не готов включить это в свой ответ.

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