• DoRubyとは
  • お問い合わせ
  • Ruby/Rails
  • Web開発
  • Webマーケティング
  • アピリッツ
  • ライフハック
  • ゲーム制作/開発
  • Railsの小技
  • Rubyの小技
  • Gemの紹介
  • ActiveRecord
  • 初心者向け
  • Java/Scalaテク
  • Unixのあれこれ
  • データベース
  • スマホ開発
  • HTML/CSS/JavaScript
  • デザイン製作
  • インフラ
  • クラウド
  • セキュリティ
  • エディタ
  • バージョン管理
  • その他
  • python
  • アクセス解析
  • Googleアナリティクス
  • Googleデータスタジオ
  • Web広告
  • SEO
  • UI/UX
  • ソーシャルメディア
  • EC開発
  • Webシステム開発
  • コンサルティング
  • Webデザイン
  • ブロックチェーン
  • ゲーム紹介
  • アプリ紹介
  • ASP
  • 風景
  • パソコン
  • ツール
  • ガジェット
  • 仕事術
  • 健康
  • 生活
  • 書評
  • Excel(エクセル)
  • PowerPoint(パワーポイント)
  • ゲームプランニング
  • SpriteStudio
  • マスターデータ入力/作成
  • Unity
  • キャラクターデザイン
  • ゲームシナリオ
  • レベルデザイン
  • ゲーム分析
  • 3DCG
  • イラスト制作
  • CG/アニメーション
  1. ホーム
  2. Ruby/Rails
  3. ActiveRecord
  4. ActiveRecord::Relationの落とし穴:解決編
  • 2017-07-03
    • カテゴリ:
    • ActiveRecord
    • タグ:
    • ActiveRecord
    • ruby
    • Rails

ActiveRecord::Relationの落とし穴:解決編

この記事は公開から1年以上が経過しています。情報が古い可能性がありますのでご注意ください。

 職場に浅草観光で買った食品サンプルを持ってきて、何も言われないのにホッとしながらも残念にも思っていたら、暫くして上長に初めて聞かれて6800円の値段に驚かれたHelloWorld!?です。
 前回の記事で、ActiveRecord::Relationに関して書きましたが(ActiveRecord::Relationの落とし穴)、上辺しか見る事が出来ていなかった、原因はもっと別の場所にあった、という事が、先輩社員や同期からの指摘で分かりました。それから自分なりに色々調べた結果、理解が深められたので、それに関して書こうと思います。

本題:ActiveRecord whereメソッド

 まず、焦点となったActiveRecord::Relation、を返すwhereメソッドに関して、その周辺も含めるソースコードを見てみました。
rails/activerecord/lib/active_record/relation/query_methods.rb

    def where(opts = :chain, *rest)
      if :chain == opts
        WhereChain.new(spawn)
      elsif opts.blank?
        self
      else
        spawn.where!(opts, *rest)
      end
    end

    def where!(opts, *rest) # :nodoc:
      opts = sanitize_forbidden_attributes(opts)
      references!(PredicateBuilder.references(opts)) if Hash === opts
      self.where_clause += where_clause_factory.build(opts, rest)
      self
    end

 ......これだけ見ても、何してるのか全く分からないです。少なくとも、ここ辺りのコードを見た事が無い自分にとっては。
 とりあえず、このコードを色々調べてみて、自分なりの擬似コードにしてみました。

    def where(条件、プレースホルダの値)
      if 引数が無かったら
        WhereChainの新しいインスタンスを返す
        #WhereChain : 条件がなかった時に、プレースホルダとして働くもの
      elsif 条件が空だったら
        自身を返す
      else
        where!(条件、プレースホルダの値)を呼ぶ
      end
    end

    def where!(条件、プレースホルダの値)
      条件の属性を確かめる
      条件がハッシュで構成されたものならば、文字列へ加工を施す
      条件を付け加える
    end

 という感じでした。
 そしてその加えられた条件は、最終的に値を取り出そうとする時にbound_attributesが呼ばれることによってSQLに代入され、レコードが取り出される、という過程を踏みます。
 自分が前回の記事で間違えた点は、その記事にも書き加えましたが、whereを呼んだだけでは条件が追加されるだけで、ActiveRecord::Relationに実際に値は入らないという事です。
 なので、それで最初から要素を入れたい時は、where(...)と呼ぶのではなくその後にloadなり適当な値を取り出すメソッドなりを呼んであげる必要がある、という事でした(where(...).loadとか)。loadをしなくとも、最終的な計測時間は変わらない訳なのですが、そこで自分は勘違いして、変な計測結果を出していたりした訳です。
 後、計測時間を、Load有りと無しでまた測ってみました。(railsコンソール上で計測)
 横軸:レコード数
 縦軸:経過時間(秒)
enter image description here
enter image description here
 ロード有りだと、ほぼほぼ時間は変わらない結果になりました。
 ただ、無しだと結構差が出ているので、ロードしてから何度も走査したりする必要があるのならば、ハッシュや配列の形式にして出力した方が良いかもしれません。

 そして、そこからもう一つ、疑問が浮かびました。
 前回の記事では、hashなどに形式を変換したら、劇的に動作速度が向上した、と書きました。実際その通りだったのですが、上記の結果を鑑みると、Load有りでは、ほぼほぼ時間は変わりませんし、Load無しにしたとしても、よほど走査を繰り返さない限り、目に見える程の差は出ないはずです。
 なら、何故......?
 と思ってその遅いコードを眺めてみようと思ったら、commitしていなかったのでもうありませんでした。
 ......。
 でも推測として、多分SQLの呼び出しを一回のループの中で複数やるようなコードを書いてしまっていたのではないか、という事が理由なのではないか、と思っています。それ以外で余り劇的な動作速度の向上が起こるような原因も思い当たりませんし。また、データを色々こねくりまわしていた所もありましたので。(またcommitに対しても、出来たコードがおかしなコードでも、キリのいいところならばコミットするようにします。過去の自分がどのように実装したか、また、他人が見た時にもcommitが小まめにされていれば、そのコーディングの軌跡が分かり易いですし。)

結論

 whereを呼んで新しく作成されるものは、SQLの条件であり、データ本体では無い。SQLを呼んでデータをロードする為には、何かしらこちらから手を加えないといけない(それに関しては、こちらの記事に詳しく書いてあります:ActiveRecord::Relationとは一体なんなのか)。
 特に、ボトルネックを調べる場合など、それが原因で混乱する可能性がある。


  • 568 views
    • Tweet
    • このエントリーをはてなブックマークに追加

この記事を書いた人
HelloWorld?
25632 256 41943041613107216 13107216384818192 256 419430418192524288168 52428816384 216 131072132768168 641282568163841310721128

「いいね!」するとDoRubyの最新記事を受け取ることができます。

Facebook

Twitterから最新記事を受け取るならこちら

Follow @doruby

Feedlyから最新記事を受け取るならこちら

follow us in feedly

おすすめの記事
  • 693 views
  • 2015-10-01
RailsのViewを自在にカスタマイズするための「Cosme」gem
  • 878 views
  • 2016-07-31
carrierwaveとfogでRiak CSへの画像アップロードを実装する

カテゴリ

Ruby/RailsRailsの小技Rubyの小技Gemの紹介ActiveRecord初心者向けWeb開発Java/ScalaテクUnixのあれこれデータベーススマホ開発HTML/CSS/JavaScriptデザイン製作インフラクラウドセキュリティエディタバージョン管理その他pythonWebマーケティングアクセス解析GoogleアナリティクスGoogleデータスタジオWeb広告SEOUI/UXソーシャルメディアアピリッツEC開発Webシステム開発コンサルティングWebデザインブロックチェーンゲーム紹介アプリ紹介ASP風景ライフハックパソコンツールガジェット仕事術健康生活書評Excel(エクセル)PowerPoint(パワーポイント)ゲーム制作/開発ゲームプランニングSpriteStudioマスターデータ入力/作成Unityキャラクターデザインゲームシナリオレベルデザインゲーム分析3DCGイラスト制作CG/アニメーション

    人気の記事
    最近の記事
    • 3,598 views
    • 2020-04-02
    Kali Linux 2020.2 導入と日本語化
    • 828 views
    • 2020-03-06
    rack-lineprofを改造して管理画面からファイル指定&ログ追跡出来るように
    • 802 views
    • 2020-03-05
    FactoryBot と Gimei を使って架空のユーザを作る
    • 584 views
    • 2020-02-04
    ActionCable実装しようwith webpack
    • 517 views
    • 2020-01-27
    この頃のプルリクに対するレビュー
    Facebook

      サイト情報
      • DoRubyとは
      • 株式会社アピリッツ

      ソーシャルアカウント
      • Facebook
      • Twitter

      企業情報
      • 会社概要
      • 採用情報
      • お問い合わせ
      サービス製品
      • レコメンドASP
      • サイト内検索ASP「Advantage Search」
      • オープンソースECサイト構築パッケージ「エレコマ」
      • 受注・在庫・商品情報一元管理「モールコネクター」
      • セキュリティ診断サービス
      • Googleアナリティクスセミナー

      Copyright © Appirits All Rights Reserved.