インデックスのない created_at を高速に検索する gem を作った

https://github.com/kmasuda050/active_record-bsearch

active_record-bsearch という gem を作った。

ログをデータベースに保存していて、巨大なテーブルになっていることがある。
BigQuery 等に移行する場合、1ファイルあたりの上限があるため、ある程度の大きさに分割したい。パーティションのことを考えると日付で分割できるのがベターだろう。作成日時にインデックスが貼られていない場合 SQL で日時指定すると、とんでもない時間がかかる。

auto increment な primary key は作成日時とほぼ同じように増加するため、
primary key を bsearch で走査し作成日時と比較することで高速に検索できるようにした。

class Post < ActiveRecord::Base
include ActiveRecord::Bsearch
end
Post.create(created_at: Time.zone.parse('2017-07-07 00:00:00'))
# => #<Post id: 1, created_at: "2017-07-07 00:00:00", updated_at: "2017-07-09 15:46:33">
Post.bsearch(Time.zone.parse('2017-07-07 00:00:00'))
# => 1
Post.bsearch(Time.zone.parse('2017-07-08 00:00:00'))
# => nil

モデルに bsearch メソッドを追加する。指定した日時のレコードがある場合、最小の primary key を返す。レコードがない場合はnilを返す。

primary key が別名であったり、作成日時のカラム名が created_at でない場合は以下のように指定する。

class Post < ActiveRecord::Base
self.primary_key = :post_id # primary key 別名
include ActiveRecord::Bsearch
end
Post.bsearch(Time.zone.parse('2017-07-07 00:00:00'), column_name: :create_time)