dogwood008の開発メモ!

最近のマイブームは機械学習, Ruby on Rails。中でも機械学習を使った金融商品の自動取引に興味があります。

【Ruby】Hash#fetchがデフォルト値を取る時、ブロックを与える方がパフォーマンスが良い

要旨

ブロックを使うのがおすすめ。

詳細

Hash#fetch は、Hashに指定したKeyが存在する際に、そのValueを返すメソッドである。

このメソッドは、指定したKeyが存在しなかった際、デフォルト値を返すことができる。その際、デフォルト値の与え方は下記の2通りある。

  • fetch(key, default_value)
  • fetch(key) { |key| default_value }

結論を先に言うと、2つ目のブロックを与える方がパフォーマンスが良くなる傾向があると言える。

1つ目は、fetchメソッドに値が渡る際、第2引数のdefault_valueが評価された後で渡る。したがって、Hash内にkeyが存在していた場合、default_valueの計算に要したリソースは全て無駄になる。

一方、2つ目はkeyがHash内に存在していなかった場合になって初めて評価される。なので、重たい処理がdefault_valueに相当する場合、ブロックで渡すことが推奨される。

なお、keyがHashに存在していなかった場合、どちらもdefault_valueが必要になるため、必要な計算リソースは変わらず、ほぼ変わらないパフォーマンスになると思われる。

参考

docs.ruby-lang.org

【JavaScript】console.log({ somevalue }) とすると変数名と値を同時に出力できて便利

要旨

console.log({ somevalue }) としてコードに埋め込んでおくと、「somevalue: (somevalueの値)」とコンソールに表示されるので、デバッグに便利。

console.log({ somevalue })とした例
console.log({ somevalue })とした例

詳細

ES2015で入った「略記プロパティ名」という記法を使うと、 object のキーと値が同じ場合に次のように略記できる。

const somevalue = '12345abcde'
のとき、
{ somevalue: somevalue }{ somevalue }
は共に同値

{ somevalue: somevalue } と { somevalue } は同値
{ somevalue: somevalue }{ somevalue } は同値

これを応用して、 console.log() に対し、この略記プロパティ名を使うと、console.logを多用している箇所でもどの値のconsole.log かを見分けることができる。

console.log({ somevalue })とした例
console.log({ somevalue })とした例

参考

qiita.com

【ActiveRecord/Rails】レコード数を数える時はcountを使うと確実、size, lengthとの違い

要旨

ActiveRecord::Relation#count を使っておくのが良い。

sizelength もあるが、キャッシュが効いて期待する値を返さない場合があるので、よほどそのような状況ではない限り、使用を避けるのが無難であろう。

やってはいけないのは、ActiveRecord::Relation#to_a

まず、一番やってはいけないのは ActiveRecord::Relation#to_a して、その Array に対して Array#size or Array#length することである。

これをするとwhereで絞り込んだ全件が一度取得された後にメモリに格納されるので、遅いしDBもアプリケーションも無駄にリソースを消費する。対象件数が少なければ良いが、例えば数万件とかの規模になってしまうと、カラムの量と割り当てメモリにもよるが、コンテナで実行していればKubernetes等のオーケストレーションツールにOOM Killされてしまうこともある。

おすすめは、 ActiveRecord::Relation#count

おすすめは、 ActiveRecord::Relation#count である。この理由は2点ある。

1つ目として、SQL の COUNTを使用してくれる点である。まずSQLサーバの中でクエリが評価される際、不要なカラムの情報を取得しない分ディスクIOも早いうえ、インデックスを使用してくれるため、全件走査と比べ処理が早い事を期待できる。

2つ目として、SQLサーバからレスポンスが返るタイミングで該当件数の数値しか返らないことである。アプリケーションサーバの使用するリソースを ActiveRecord::Relation#to_a と比べ大幅に節約することが可能である。

他にもsize length もあるが、使用には注意が必要

ActiveRecord::Relation#size ActiveRecord::Relation#length もあるが、クエリ内容によってはキャッシュが効くため注意が必要。

具体的には、キャッシュの使用有無が参考にした文献で紹介されているものの、根拠となっている実装は、現在の最新 main ブランチだと削除されているメソッドのため、真偽不明で調査検証の必要がある。

結局どうすれば良いか

count を使っておけば、キャッシュ無しで取得できることが保証されているようである。なので、ActiveRecordのパフォーマンスをよほどシビアに要求されるような箇所でなければ、 count を使用するのが安全ではないか、という結論にしたい。

実装

ActiveRecord::Relation#size

github.com

ActiveRecord::Caluculations#count

ActiveRecord::Relationinclude されている

github.com

ActiveRecord::ConnectionAdapters::StatementPool

github.com

ActiveRecord::Result#length

github.com

参考

bhserna.com

ohbarye.hatenablog.jp

qiita.com

www.lanches.co.jp