Edited at

SQLアンチパターンon Rails Ⅲ部(クエリ)

More than 1 year has passed since last update.


はじめに

SQLアンチパターンをRailsの文脈で読み解いていきます。

この記事では、Ⅲ部 クエリのアンチパターン(13~18章)を取り上げます。


リンク


本文


13. フィア・オブ・ジ・アンノウン(恐怖のunknown)

null: falseを適切につけましょう。

nullが嫌だからって、退職日に2100-12-31みたいな謎の値を入れるのはNG。

&.(ぼっち演算子)とかtryとか||を適切に使ったらそこまで苦しめられることもない気もする。


14. アンビギュアスグループ(曖昧なグループ)

グループ内で最大値を持つ行を取得する、というのはActiveRecordだと無理っぽい。

パフォーマンスを妥協できるなら、rubyのコードで何とかする手はありますが、

そうでなければ、SQL書く(できれば、Window関数のRANK()とかを使いたい)とよいと思います。

そして、生SQL書くならクエリオブジェクトを作るのがよさそう。


15. ランダムセクション

Bug.order('random()').take(1) # PostgreSQLの場合。MySQLだと`RAND()`ですかね。

がダメという話。1件取ればいいだけなのに、無駄に全件ランダムソートしているので遅い。とはいえ、

# NG

Bug.all.sample(1)

よりは遥かにましだし、

# NG

Bug.find(Bug.ids.sample(1))

よりも良さげ。

ただ、本に書いてある通り、以下がベスト。

# Best

Bug.offset(rand(Bug.count)).take(1)

(参考:【Ruby on Rails】テーブルのレコード数を取得する - Modelのコメント欄)


16. プアマンズ・サーチエンジン(貧者のサーチエンジン)

ElasticSearchとか。


17. スパゲッティクエリ

クエリが複雑にならないように、「困難は分割せよ」という話。

Railsにおいては、scopeを切ったりすることがそれにあたりそう。

とはいえ、ActiveRecordでやってる限り、そんな滅多なことにならないのではという気がする。

そうなりやすいのは生SQLを書くときで、そのときの対処は本を参考に。

WITH句とか使うと少しわかりやすくなるか?


18. インプリシットカラム(暗黙の列)

select(:id, :name)とかすると、カラムが絞れますが、メソッド呼び出しでどのカラムが必要とかあまり気にしたくないので、使うことがあまりない。

とはいえ、カラム数が非常に多い場合selectも必要になってくるかもしれません。

RubyのArrayが欲しい場合には、pluck(:id, :name)なんかも使えますね。