Ka Mok Ka Mok - 3 months ago 12
Ruby Question

What is the difference between using Active Record exists? versus find_by ?

In my model, I check if a

Sudoku
record exists in the database first before I either fetch it's
solution
or create it.

if Sudoku.exists?(puzzle: puzzle)
return Sudoku.find_by(puzzle: puzzle).solution
else
**solve it and save it into the db**
end


What is the difference from doing this:

if Sudoku.find_by(puzzle: puzzle)
return Sudoku.find_by(puzzle: puzzle).solution
else
**solve it and save it into the db**
end


Logs for
exists?


Sudoku Exists (0.0ms) SELECT 1 AS one FROM "sudokus" WHERE "sudokus"."puzzle" = $1 LIMIT 1 [["puzzle", "390820700801500069020160403002096058935000602060752030703941000200037590019000347"]]
Sudoku Load (0.0ms) SELECT "sudokus".* FROM "sudokus" WHERE "sudokus"."puzzle" = $1 LIMIT 1 [["puzzle", "390820700801500069020160403002096058935000602060752030703941000200037590019000347"]]
Completed 200 OK in 8ms (Views: 0.2ms | ActiveRecord: 3.0ms)


Logs for
find_by


Sudoku Load (0.0ms) SELECT "sudokus".* FROM "sudokus" WHERE "sudokus"."puzzle" = $1 LIMIT 1 [["puzzle", "390820700801500069020160403002096058935000602060752030703941000200037590019000347"]]
CACHE (0.0ms) SELECT "sudokus".* FROM "sudokus" WHERE "sudokus"."puzzle" = $1 LIMIT 1 [["puzzle", "390820700801500069020160403002096058935000602060752030703941000200037590019000347"]]
Completed 200 OK in 7ms (Views: 0.2ms | ActiveRecord: 2.0ms)


At first, I thought by doing two
find_by
it would hit the database twice, but then I see the CACHE. Does that mean Rails remember the previous query in the first
find_by
and is only hitting it once?

Why would I use
exists?
over
find_by
?

Answer

Rails wraps each controller action with a simple query cache. The CACHE in the logs does indicates that the query was served from the cache. If you were to run that code in the console you wouldn't get that caching (unless you explicitly set that up).

The difference query wise is that none of the fields of the object are fetched from the database. Aside from the network impact, depending on the query and the indices present, your database may be able to use a covering index (in a nutshell the index can be used to answer the query completely instead of the db using the index to find the data for the row)

On top of that rails doesn't construct an active record object from the result, you just get back true/false.

So exists? is faster. However it's pointless if you then call find_by straight after. You might as well call find_by once only.

Comments