Reputation: 1988
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
?
Edit:
From advice, I'm using this now:
if sudoku = Sudoku.find_by(puzzle: puzzle)
return sudoku.solution
else
**solve it and save it into the db**
end
Upvotes: 4
Views: 2480
Reputation: 84114
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.
Upvotes: 9