拝啓〜データベースにIndex貼ってますか?〜


はじめに

突然ですが、データベースにインデックスって貼ってますか??
「なにそれ?」や「知ってるけど貼る方法が微妙。。」な人も、この記事で適切にインデックスを貼れるようになります!
知識を蓄えてデータの読み込み速度の上昇を目指しましょう!

まず、インデックスとは?

特定のカラムからデータを取得する際に、テーブルの中の特定のカラムのデータを複製し検索が行いやすいようにしたもののことです。

例えでいうと、Userテーブルの名前データを参照したいと考えた場合、Usersテーブルのnameカラムにindexを張ってないと、プログラムはUserテーブルのnameカラムを上から順にみていくので対象データが一番下の場合とても時間がかかります。
それを解決するのがインデックスです!

メリット and デメリット

  • メリット
    • データの読み込み・取得が早くなる。
  • デメリット
    • 書き込みの速度が倍かかる。

どのカラムにインデックスを貼ればいいの?

データ量が多いテーブルの、格納される値がそれぞれ異なるようなカラムで、検索がよく行われるカラムに対して張るととても効果的です。
-例-
外部キー、よく検索に使われるカラム...etc

インデックスの貼り方

1.rails g migration add_index_テーブル名_カラム名とし、migrationファイルを作成する。


class AddIndexToテーブル名 < ActiveRecord::Migration
  def change
    add_index :テーブル名, カラム名
    add_index :テーブル名, [:カラム名1, :カラム名2, ・・・] # 複数カラムに貼る場合
    add_index :テーブル名, カラム名, unique: true # ユニークなインデックスを生成
    add_index :テーブル名, カラム名, length: 15 # インデックスの長さを15に指定して生成
    add_index :テーブル名, カラム名, name: 'index' # インデックス名をつけて生成
  end
end

※追加ではなく、最初のテーブル作成時にインデックスを貼る場合は、以下のようにする。


class CreateHoges < ActiveRecord::Migration
    def change
        create_table :hoges do |t|
            # index: trueとする
            t.references :huga, index: true, foreign_key: true, null: false
            t.string :fuga, null: false     
            t.timestamps null: false
        end
    end
end

2.ファイル作成後、rails db:migrateを実行する。

複合インデックスというものもあります

1つのカラムだけにインデックスを貼ると、全てのカラムが一致するような検索結果を出すためには、一つ目のカラムで調べて、重複する中から2つ目のカラムで一致するものを調べて、と順々に調べる必要があります。
このような事態を防ぐため、複合インデックスを予め貼っておくと、高速で検索が可能になるという利点があります。

複合インデックスの特徴

複合インデックスは、「キーとして構成されているカラムの全てが検索条件に指定されていなくても、キーの先頭から途中までのカラムが指定されていれば、インデックスが使われる」という特徴があります。
インデックスで全ての情報を事細かく指定してしまうと、不必要な情報をも毎回検索してしまうので、 複合インデックスでの指定ではカラムの一部だけを指定すればよいことになります。

-例-
会社(companyテーブル)、姓(family_nameカラム)、名(personal_nameカラム)、誕生日(birthdayカラム)とあるとする。
会社(companyテーブル)の内容が90%がA社で,10%がB社といった情報量の少ない場合は、姓と名で複合インデックスを貼れば良い。

注意点

インデックス名は以下のルールに則って命名されます。
1.index_テーブル名_on_〇〇とする
2.単独のインデックスはカラム名を追加する
3.複合インデックスは、カラム名を_and_で連結する。

# 単独インデックスの場合
add_index :customers, :family_name_kana
#=> "index_customers_on_family_name_kana"

# 複合インデックスの場合
add_index :customers, [ :family_name_kana, :given_name_kana ]
#=> "index_customers_on_family_name_kana_and_given_name_kana"

# 複合インデックスの場合(3つ以上)
add_index :customers, [ :birth_month, :family_name_kana, :given_name_kana ], name: "index_customers_on_birth_month_and_furigana"
#=> name属性を指定しないとエラーとなるため自分で命名する

おわりに

ここまで説明されたら、0知識でも少しだけイメージが湧きましたでしょうか?
データが膨大になってくると、読み込み速度はとても重要です。
適切にインデックスを貼れるようにしておきましょう!!

参考

データベースにindexを張る方法

Railsマイグレーションのindexの定義方法と対象について

Rails 複合インデックスの貼り方