ホーム DoRuby 【Rails】巨大なテーブル同士をjoinせずに検索【速度改善】
【Rails】巨大なテーブル同士をjoinせずに検索【速度改善】
 

【Rails】巨大なテーブル同士をjoinせずに検索【速度改善】

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

巨大なテーブル同士をjoinしてから検索すると遅くなるのでjoinせずに検索する方法を記述します。

例として下記のようなテーブル関連とします。

Post ー* TagPost ー* Tag
 |
 *
Comment

# 投稿
class Post < ActiveRecord::Base
  has_many :comments
  has_many :post_tags
  has_many :tags, though: :post_tags
end

# 中間テーブル
class PostTag< ActiveRecord::Base
  belongs_to :post
  belongs_to :tag
end

# タグ
class Tag < ActiveRecord::Base
  has_many :post_tags
  has_many :posts, though: :post_tags
end

# コメント
class Comment < ActiveRecord::Base
  belongs_to :post
end

上記の状態でコメントとタグのタイトルに「あ」という文字が入っている投稿を取得したい場合はテーブルをjoinして検索すると思います。

Post.joins(:comments, :tags).where(['comments.title LIKE ? AND tags.title LIKE ?', '%あ%', '%あ%' ])

ですががレコード数がそれぞれ数十万件以上だった場合とてもjoinしていられません。かなり遅くなるかと思います。そこで

それぞれのテーブルでpost_idを取得してそれをもとにPostを取得する

# コメントのpost_id取得
comment_post_ids = Comment.where(['title LIKE ?',  '%あ%']).pluck(:post_id)

# タグのid取得
tag_ids = Tag.where(['title LIKE ?',  '%あ%']).pluck(:id)

# タグのpost_id取得
tag_post_ids = PostTag.where(tag_id: tag_ids).pluck(:post_ids)

# 取得したpost_idが一致しているものを取得
post_ids = comment_post_ids & tag_post_ids

# 投稿を検索!
posts = Post.where(id: post_ids)

ポイント

  • pluckを使う
  • 取得したidたちで「&アンド」(どちらかに入っていればいい場合「|オア」)を取る

SQLを複数回実行しますが巨大なテーブル同士をjoinするよりは早くなることがあります。

記事を共有

最近人気な記事