• 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. Railsの小技
  4. counter_cacheを使ってみよう
  • 2010-03-18
    • カテゴリ:
    • Railsの小技

counter_cacheを使ってみよう

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

今回はcounter_cacheの使い方を紹介します。
counter_cacheとは、RailsのActiveRecordでRDB関連の設定の1つです。
これを設定することにより、親子関係のテーブルにおいて、親テーブルが子テーブルの
件数をキャッシュすることができるようになります。
例えばいろんな商品のクチコミサイトがあるとします。

そこでは各商品毎にクチコミを複数件登録することができ、
商品一覧ページにクチコミ件数を表示したり、クチコミ件数が多い順に並び替えたりできる、という設定です。

さて、クチコミ件数が多い順に並び替える時はどんなSQLを発行しましょうか。

商品とクチコミは1対多の関係なので、各テーブルとカラムは以下の通りです。
(今回の説明に必要ないモノは省いています)

・商品(親テーブル)
モデル名:Item
テーブル名:items
カラム:id, name

・クチコミ(子テーブル)
モデル名:Comment
テーブル名:comments
カラム:id, item_id, comment

・クチコミのモデル内での商品との紐付け設定
class Comment < ActiveRecord::Base
  belongs_to :item
end

この場合、発行されるSQLはこんな感じです。
select *,
       (select count(*) from comments where comments.item_id=items.id ) as count
from items
order by count desc;

Rails的な書き方だと
Item.find(:all,
          :select => "*,(select count(*) from comments where comments.item_id=items.id ) as count",
          :order => "count desc")
こうなります。

動けば何でも良いのであればこれで良いのですが、このやり方だとデータ量が増えた時に処理が重くなる原因になります。
対象の商品の全クチコミをカウントするので当然「index?なにそれ?」状態です。


さすがに↑のやり方は重いですが、こういう書き方もできます。
SELECT items.id, count(comments.id) as count
FROM items
      left join comments on comments.item_id=items.id
group by items.id
order by count desc;

Rails的な書き方だと
Item.find(:all,
          :select => "items.*, count(comments.id) as count",
          :joins => "left join comments on comments.item_id=items.id",
          :group => "items.id",
          :order => "count desc")
こうなります。
子テーブルをleft joinで引っ張ってきて、group化する事でカウント処理を行わないようにしました。

…SQLが目に見えて複雑化していますね。
先程の1件ごとのカウントよりはだいぶマシですが、indexが使えないので後々重くなると思います。
また、group byの指定は使用するDBがMySQLの時のみこの書き方が使用可能です。
postgresの場合はselectする項目(countを除く)をすべて指定する必要があります。かなり面倒です。
今回の例題はitemsテーブルのカラムがid, nameだけなので全部書けば良いですが、実際の開発ではこんなにカラムが少ないわけもなく、
開発現場から悲鳴が聞こえてくるハメになります…。


そこで今回紹介するcounter_cacheの出番です。
先程紹介したテーブルのカラム、及びモデルの設定を以下のように追加します。

・商品(親テーブル)
モデル名:Item
テーブル名:items
カラム:id, name, comments_count

・クチコミ(子テーブル)
モデル名:Comment
テーブル名:comments
カラム:id, item_id, comment

・クチコミのモデル内での商品との紐付け設定
class Comment < ActiveRecord::Base
  belongs_to :item, :counter_cache => true
end

itemsテーブルに追加したcomments_countは:default => 0にする必要があります。
これだけでクチコミが増えたり減ったりした時にカウントを計測してitemsテーブルのcomments_countに保存されるようになります。

先程のSQLも以下のように変化します。
select *
from items
order by comments_count desc;

Rails的な書き方だと
Item.find(:all,
          :order => "comments_count desc")
こうなります。

これならリスト取得時にクチコミ数をカウントする手間がなくなり、
またcomments_countにindexを貼ることができるため処理速度が改善されます。
是非何かの役立ててください。
それでは。

GOOD RAILS!!

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

この記事を書いた人
honda
アピリッツでWebプログラマーをやっているhondaです。 Ruby on Railsで開発をしています。 ここではRuby on Railsのプログラミングに役立ちそうな小技を紹介していきたいと思います。

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

Facebook

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

Follow @doruby

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

follow us in feedly

おすすめの記事
  • 695 views
  • 2015-10-01
RailsのViewを自在にカスタマイズするための「Cosme」gem
  • 907 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/アニメーション

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

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

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

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

      Copyright © Appirits All Rights Reserved.