Rails 5+の場合(Ruby2.4.1およびPostgres9.6)
私は100foos
と9900を持っていbars
ます。それぞれの99にfoos
は100bars
があり、そのうちの1つにはありません。
Foo.left_outer_joins(:bars).where(bars: { foo_id: nil })
1つのSQLクエリを生成します。
Foo Load (2.3ms) SELECT "foos".* FROM "foos" LEFT OUTER JOIN "bars" ON "bars"."foo_id" = "foos"."id" WHERE "bars"."foo_id" IS NULL
Foo
そしてないものを返しますbars
現在受け入れられている回答Foo.where.not(id: Bar.select(:foo_id).uniq)
は機能していません。2つのSQLクエリを生成しています。
Bar Load (8.4ms) SELECT "bars"."foo_id" FROM "bars"
Foo Load (0.3ms) SELECT "foos".* FROM "foos" WHERE ("foos"."id" IS NOT NULL)
すべてがnullではないを持っているfoos
ので、これはすべてを返します。foos
id
Foo.where.not(id: Bar.pluck(:foo_id).uniq)
1つのクエリに減らして、を見つけるにはに変更する必要がありますFoo
が、ベンチマークではパフォーマンスが低下します
require 'benchmark/ips'
require_relative 'config/environment'
Benchmark.ips do |bm|
bm.report('left_outer_joins') do
Foo.left_outer_joins(:bars).where(bars: { foo_id: nil })
end
bm.report('where.not') do
Foo.where.not(id: Bar.pluck(:foo_id).uniq)
end
bm.compare!
end
Warming up --------------------------------------
left_outer_joins 1.143k i/100ms
where.not 6.000 i/100ms
Calculating -------------------------------------
left_outer_joins 13.659k (± 9.0%) i/s - 68.580k in 5.071807s
where.not 70.856 (± 9.9%) i/s - 354.000 in 5.057443s
Comparison:
left_outer_joins: 13659.3 i/s
where.not: 70.9 i/s - 192.77x slower