2013-11-08 3 views
1

я следующие соотношения между записями: enter image description hereActive Record Query для Дальней Ассоциации

Учитывая рекорд Project Мне нужен список всех стран, связанных со всеми ресурсами связанных с Проект. Ни одна страна не должна появляться более одного раза.

Чтобы сделать это, игнорируя очевидные проблемы производительности, я мог бы добавить метод ресурсов:

def countries 
    resources.flat_map{|resource| resource.countries}.uniq 
    end 

Мой вопрос два раза.

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

[Update]

@ предложение MarekLipka является:

resources.includes(:countries).map(&:countries).flatten.uniq 

Однако это приводит к 60 хитов, всего за 0,4 секунды для 20 проектов:

ресурсов Load (1.2ms) SELECT "resources". * FROM "resources" WHERE "resources". "Project_id" = 20 ORDER BY name

ResourceLocation Load (1.0ms) SELECT «resource_locations». * FROM «resource_locations» WHERE «resource_locations». «Resource_id» IN (97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126)

Страна нагрузки (0,4 мс) ВЫБОР "страны". * FROM "стран", где "страны". "идентификатор" IN (19, 31, 64, 82, 197, 169, 1, 161, 167)

[Обновление]

Моя последняя попытка приходит примерно в два раза быстрее, чем выше решение за счет использования joins, а не includes, делая 1 попадание на ресурс в общей сложности ~ 0,2 секунды:

Country.joins(resource_locations: {resource: :project}).where(resources: {project_id: self}).uniq 

ответ

1

Это должно быть в порядке:

resources.includes(:countries).map(&:countries).flatten.uniq 

includes метод решает проблему N + 1 запросов путем предварительной загрузки соответствующих ассоциаций.

+0

Это приводит к 3 ударам за ресурс. См. Обновление, о котором идет речь. – Undistraction

Смежные вопросы