0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Activerecord tablehoges.present? と last の組み合わせの罠

Posted at

自分用のメモです。

TiDB環境で顕在化した。
tablehoges.present? などの事前ロードを済ませる系の処理以降で、同 tablehoges オブジェクトに対して tablehoges.last といった整列ありきで1件取得した場合に予期せぬデータが取得された。
原因は present? による事前ロードと present? でロードした同 ActiveRecord_Relation のオブジェクトに対して last を使用したこと。

アンチパターン

if tablehoges.present? # ← ORDER BY なしで全件ロードが走る
  latest = tablehoges.last # ← ↑で事前ロードしたメモリ上の不定順序の配列の末尾を使ってしまう
end

ベストプラクティス

例1

わかりやすい。
ただし、当該処理がN+1が発生しうる処理かどうかの検討は必要。

if tablehoges.exists? # ← EXISTS クエリのみ。レコード自体はロードしない
  latest = tablehoges.order(:id).last # ← 明示的にソートしてから取得
end

例2

クエリも1回なのでスマート。

last_record = tablehoges.order(:id).last # ← ORDER BY を明示
if last_record
  latest = last_record
end

終わりに

当然ですが、order 句がなければ順番が保証されないデータとして取得されます。
自分が驚いたのは present? が事前ロードしているという点です。
ActiveRecord_Relationlast ってつけたら order(:id) という解釈になりクエリが発行されると思っていました。
気をつけます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?