As @The russian shame said your query perfomance is good enough
I just add another query with EXISTS
to compare
You can use where_exists
gem for this purpose as
User.where_not_exists(:subscriptions, premium: true)
EXPLAIN ANALYZE SELECT * FROM users WHERE (NOT (EXISTS (SELECT 1 FROM subscriptions WHERE (subscriptions.user_id = users.id) AND premium = TRUE)));
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------
Hash Anti Join (cost=123.50..153.00 rows=9 width=24) (actual time=2.652..3.357 rows=91 loops=1)
Hash Cond: (users.id = subscriptions.user_id)
-> Seq Scan on users (cost=0.00..17.00 rows=1000 width=24) (actual time=0.020..0.264 rows=1000 loops=1)
-> Hash (cost=92.00..92.00 rows=2520 width=8) (actual time=2.617..2.618 rows=2520 loops=1)
Buckets: 4096 Batches: 1 Memory Usage: 131kB
-> Seq Scan on subscriptions (cost=0.00..92.00 rows=2520 width=8) (actual time=0.013..1.653 rows=2520 loops=1)
Filter: premium
Rows Removed by Filter: 2480
Planning Time: 0.504 ms
Execution Time: 3.409 ms
(10 rows)
EXPLAIN ANALYZE SELECT * FROM users WHERE users.id NOT IN (SELECT user_id FROM subscriptions WHERE premium = TRUE);
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------
Seq Scan on users (cost=98.30..117.80 rows=500 width=24) (actual time=0.722..0.878 rows=91 loops=1)
Filter: (NOT (hashed SubPlan 1))
Rows Removed by Filter: 909
SubPlan 1
-> Seq Scan on subscriptions (cost=0.00..92.00 rows=2520 width=8) (actual time=0.004..0.415 rows=2520 loops=1)
Filter: premium
Rows Removed by Filter: 2480
Planning Time: 0.055 ms
Execution Time: 0.899 ms
(9 rows)