如何在Rails中使用参数避免范围内的N + 1查询

时间:2018-10-20 11:15:16

标签: ruby-on-rails

在这种情况下,我遇到了N + 1问题:

Library有许多Programs。现在,我想让所有程序都位于某个国家/地区,因此我有一个代码:

country = "US"
programs = @libraries.includes(:programs).map do |library|   
  library.programs.where(country: country)
end

但是现在有N + 1个问题:

Program Load (0.8ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 15], ["country", "US"]]
Program Load (0.4ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 73], ["country", "US"]]
Program Load (0.5ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 27], ["country", "US"]]
Program Load (0.3ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 177], ["country", "US"]]
Program Load (0.3ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 38], ["country", "US"]]
Program Load (0.4ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 51], ["country", "US"]]
Program Load (0.6ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 18], ["country", "US"]]
Program Load (0.3ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 20], ["country", "US"]]
Program Load (0.5ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 42], ["country", "US"]]
Program Load (0.5ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 39], ["country", "US"]]

更新

我的目的不是仅仅过滤programs,而是要使用它。例如:

programs = @libraries.includes(:programs).each do |library|   
  if library.programs.where(country: country).size < 5
    puts "US programs are less than 5 so you can still add"
  end
end

有人知道如何解决N + 1问题吗?

1 个答案:

答案 0 :(得分:1)

您可以 where查询链接到includes,如下所示

programs = @libraries.includes(:programs).where(programs: {country: country})

应该可以解决 N + 1 问题。

请参见specifying-conditions-on-eager-loaded-associations

更新#1:

您可以这样简单地完成

programs = @libraries.includes(:programs).where(programs: {country: country}).size < 5 #returns true or false

if programs #true
  puts "US programs are less than 5 so you can still add"
else #false
  #your code
end

更新#2:

这应该做

programs_size = @libraries.includes(:programs).where(programs: {country: country}).map { |library| library.programs.size }

仅执行一个查询,并返回与条件匹配的每个library.programs的大小作为数组,如下所示< / p>

=> [5, 4, 7, 4, 6, 2, 1]

现在您可以遍历programs_size数组并执行逻辑

programs_size.each do |ps|
  if ps < 5 #true
    puts "US programs are less than 5 so you can still add"
  else #false
    #your code
  end
end