Skip to content

Instantly share code, notes, and snippets.

@alpaca-tc
Created May 23, 2021 14:07
Show Gist options
  • Save alpaca-tc/6c3dcd979e27547be688add4e1619294 to your computer and use it in GitHub Desktop.
Save alpaca-tc/6c3dcd979e27547be688add4e1619294 to your computer and use it in GitHub Desktop.
ActiveRecordでUSE INDEXを使うための拡張
module WithIndex
extend ActiveSupport::Concern
class IndexNotFound < StandardError; end
class_methods do
# インデックスを指定する
#
# @example
# User.where(...).use_index([:group_id, :created_at]).load
#
# 渡す値にはインデックス名か、インデックスに利用されているカラムを指定できる
# https://github.com/rails/rails/issues/27110#issuecomment-478385713 の仕様に合わせた
#
# @param index [Array<#to_s>, #to_s]
#
# @return [ActiveRecord::Relation]
def use_index(index)
index_name = resolve_index_name(index)
from("#{quoted_table_name} USE INDEX (#{index_name})")
end
private
def resolve_index_name(index)
case index
when Array
# 利用されるカラムが一致しているインデックスを探す。
# B-treeの想定なので、期待するインデックスが先頭から順に含まれていればOK
index = index.map(&:to_s)
index_definition = connection.indexes(table_name).find { _1.columns[0..index.size - 1] == index }
index_definition&.name || raise(WithIndex::IndexNotFound, index.to_s)
when String, Symbol
index.to_s
else
raise NotImplementedError, "not supported #{index.class}"
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment