Rails環境でのMySQLインデックス付与効果の調査

# 概要
Rails環境でのMySQLインデックスの効果を調査します。

# 目的
インデックスがの効果を理解したうえで、インデックスを設定できるようになること。

# 環境
* WSL2
    * Ubuntu 20.04.2 LTS (GNU/Linux 4.19.128-microsoft-standard x86_64)
* Rails
    * version 6.1.4.4
    * Ruby 2.7.2
* MySQL
    * 8.0.27 Community Server

# テスト用プロジェクト作成
## プロジェクトディレクトリの作成
```bash:ターミナル
$ mkdir considerable_db_select
```

## Gemfile作成・編集
プロジェクトディレクトリに移動し、Gemfileを作成します。

```bash:ターミナル
$ cd considerable_db_select
$ touch Gemfile
```

Gemfileを編集し、Railsのバージョンを指定します。

```Gemfile:Gemfile
source 'https://rubygems.org'
gem 'rails', '6.1.4.4'
```

## Railsプロジェクト作成
先程作成したGemfileを基にRailsプロジェクトを作成します。

```bash:ターミナル
$ rails new . --database=mysql
```


# モデル作成
Railsコマンドでモデルを作成します。

```bash:ターミナル
$ rails g model user
Running via Spring preloader in process 194
      invoke  active_record
      create    db/migrate/20220106143118_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
```

## Modelの定義
今回は3つのカラムに対してインデックス、複合インデックスを付与して試験をします。

```ruby:db/migrate/20220106143118_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      t.string :name, comment: '名前'
      t.string :email, comment: 'メールアドレス'
      t.integer :age, limit: 1, unsigned: true, comment: '年齢'
      t.timestamps
    end
  end
end
```

変更したModel定義をRailsコマンドで反映します。

```bash:ターミナル
$ rails db:migrate
Running via Spring preloader in process 208
== 20220106143118 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0511s
== 20220106143118 CreateUsers: migrated (0.0512s) =============================
```

# 大量のデータを投入
今回は試験のため`seeds.rb`で大量のデータを追加します。
並列でDBへ挿入しないと非常に時間がかかるので`parallel`gemを利用して行います。

## `parallel gem`の追加
Gemfilへ追加し、`bundle install`でGemを追加します。

```Gemfile:Gemfile
gem `parallel`
```
```bash:ターミナル
$ bundle install
```

## Seedファイルを設定

```ruby:db/seed.rb
# parallelを利用して5スレッド並列で10万レコードのテストデータを挿入
# -> `in_threads`は`config/database.yml`の`pool`の値を設定する
Parallel.each(1..100_000, in_threads: 5) do |n|
  ActiveRecord::Base.connection_pool.with_connection do
    User.create!(
      name: "テスト太郎#{rand(1..9999)}",
      email: "test#{rand(1..9999)}@example.com",
      age: rand(0..150)
    )
  end
end
```
自分の環境では15分程度でデータの挿入が完了しました。


# ベンチマーク計測用ファイルの作成
ベンチマークを用いて問い合わせ時のパフォーマンスを計測します。
ベンチマーク計測用ファイルはプロジェクト直下に作成します。

```ruby:select_benchmark_all.rb
require 'benchmark'

# 問い合わせ回数
REPEAT_TIMES = 500.freeze

def start_benchmark
  # find_byのベンチマークを行う際にログが死ぬほど出るので、ベンチマークの間だけDB問い合わせログの表示を無効化
  prev_logger = ActiveRecord::Base.logger
  ActiveRecord::Base.logger = nil

  # タイトルを表示する領域を15字分設定
  Benchmark.bm 15 do |r|
    r.report "name" do
      REPEAT_TIMES.times do
        User.find_by(name: "test#{rand(1..100000)}")
      end
    end

    r.report "email" do
      REPEAT_TIMES.times do
        User.find_by(email: "test#{rand(1..100000)}@example.com")
      end
    end

    r.report "age" do
      REPEAT_TIMES.times do
        User.find_by(age: rand(0..150))
      end
    end

    r.report "name_email" do
      REPEAT_TIMES.times do
        User.find_by(name: "テスト太郎#{rand(1..100000)}", email: "test#{rand(1..100000)}@example.com")
      end
    end

    r.report "name_age" do
      REPEAT_TIMES.times do
        User.find_by(name: "テスト太郎#{rand(1..100000)}", age: rand(0..150))
      end
    end

    r.report "name_email_age" do
      REPEAT_TIMES.times do
        User.find_by(name: "テスト太郎#{rand(1..100000)}", email: "test#{rand(1..100000)}@example.com", age: rand(0..150))
      end
    end

    r.report "name_age_email" do
      REPEAT_TIMES.times do
        User.find_by(name: "テスト太郎#{rand(1..100000)}", age: rand(0..150), email: "test#{rand(1..100000)}@example.com")
      end
    end

    r.report "email_name" do
      REPEAT_TIMES.times do
        User.find_by(email: "test#{rand(1..100000)}@example.com", name: "テスト太郎#{rand(1..100000)}")
      end
    end

    r.report "email_age" do
      REPEAT_TIMES.times do
        User.find_by(email: "test#{rand(1..100000)}@example.com", age: rand(0..150))
      end
    end

    r.report "email_name_age" do
      REPEAT_TIMES.times do
        User.find_by(email: "test#{rand(1..100000)}@example.com", name: "テスト太郎#{rand(1..100000)}", age: rand(0..150))
      end
    end

    r.report "email_age_name" do
      REPEAT_TIMES.times do
        User.find_by(email: "test#{rand(1..100000)}@example.com", age: rand(0..150), name: "テスト太郎#{rand(1..100000)}")
      end
    end

    r.report "age_name" do
      REPEAT_TIMES.times do
        User.find_by(age: rand(0..150), name: "テスト太郎#{rand(1..100000)}")
      end
    end

    r.report "age_email" do
      REPEAT_TIMES.times do
        User.find_by(age: rand(0..150), email: "test#{rand(1..100000)}@example.com")
      end
    end

    r.report "age_name_email" do
      REPEAT_TIMES.times do
        User.find_by(age: rand(0..150), name: "テスト太郎#{rand(1..100000)}", email: "test#{rand(1..100000)}@example.com")
      end
    end

    r.report "age_email_name" do
      REPEAT_TIMES.times do
        User.find_by(age: rand(0..150), email: "test#{rand(1..100000)}@example.com", name: "テスト太郎#{rand(1..100000)}")
      end
    end
  end
  # ロガーにSQLログが表示されるように再設定
  ActiveRecord::Base.logger = prev_logger
  # ベンチマークのインスタンスを表示されても困るのでnilを戻す
  nil
end
```

<details><summary>+α. ベンチマーク時にロガーの設定をしている理由</summary><div>

ベンチマークをそのまま実行すると`find_by`のSQLログが**繰り返し回数分だけ出力されます**。

```
                      user     system      total        real
name              User Load (0.5ms)  SELECT `users`.* FROM `users` WHERE `users`.`name` = 'test7587' LIMIT 1
  User Load (0.5ms)  SELECT `users`.* FROM `users` WHERE `users`.`name` = 'test65641' LIMIT 1
  User Load (0.5ms)  SELECT `users`.* FROM `users` WHERE `users`.`name` = 'test24924' LIMIT 1
  User Load (0.4ms)  SELECT `users`.* FROM `users` WHERE `users`.`name` = 'test86882' LIMIT 1
  User Load (0.5ms)  SELECT `users`.* FROM `users` WHERE `users`.`name` = 'test55158' LIMIT 1
  User Load (0.6ms)  SELECT `users`.* FROM `users` WHERE `users`.`name` = 'test20788' LIMIT 1
  User Load (0.8ms)  SELECT `users`.* FROM `users` WHERE `users`.`name` = 'test74850' LIMIT 1
  User Load (0.6ms)  SELECT `users`.* FROM `users` WHERE `users`.`name` = 'test33180' LIMIT 1
  User Load (0.6ms)  SELECT `users`.* FROM `users` WHERE `users`.`name` = 'test61106' LIMIT 1
  User Load (0.5ms)  SELECT `users`.* FROM `users` WHERE `users`.`name` = 'test35902' LIMIT 1
  ...
  合計500件分の問い合わせレコード
  ...
  0.124768   0.004476   0.129244 (  0.165278) <- 計測結果がヘッダと離れてしまうので、非常に見にくい
```

以下の設定でSQLログを非表示にし、ベンチマークの結果が流れないようにしています。

```
ActiveRecord::Base.logger = nil
```

</div></details>

# ベンチマークでの速度計測
モデルの情報を取得する必要があるため、`rails c`で`irb`を起動してベンチマークファイルを呼び出します。

```bash:ターミナル
$ rails c
```
```irb:irb
irb(main):001:0> require './select_benchmark_all.rb'
=> true
irb(main):002:0> 3.times do start_benchmark end
```

## ベンチマークのルール
以下のルールでベンチマークを計測し、結果の比較を行うこととしました。

* 10万件のレコードをベンチマークの対象とする
* ベンチマークは以下の条件で計測する
    * インデックスなし
    * インデックスあり
        * 各カラムにインデックスを付与
        * Whereに沿った複合インデックスを付与
* 各条件で3回ベンチマークを取得し、各項目の平均を比較値として利用する

最終的には以下の2パターンで`real`以外の項目について性能がどの程度上がったかを確認します。
（`real`は経過時間そのもので、CPUがぼーっとしている時間も含まれるので見る必要がないとのこと）

1. Indexなし VS 各カラムにインデックスを付与
1. Indexなし VS Whereに沿った複合インデックスを付与

## 結果

### 1. インデックスなし VS 各カラムにインデックスを付与
|  | インデックスなし |  |  |  | インデックスあり |  |  |  | indexなし / インデックスあり |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 項目名/区分 | user | system | total | real | user | system | total | real | user | system | total | real |
| name | 0.119977 | 0.05756 | 0.17753699999999997 | 12.037523 | 0.09258533333333334 | 0.030229000000000002 | 0.12281433333333334 | 0.185155 | 1.2958531948904792 | 1.9041317939726752 | 1.445572313763594 | 65.01322135508089 |
| email | 0.13663166666666668 | 0.030953000000000005 | 0.1675846666666667 | 11.741430999999999 | 0.09361033333333334 | 0.015792333333333335 | 0.10940266666666666 | 0.16877 | 1.4595788926436184 | 1.9600016885830678 | 1.5318151903670845 | 69.57060496533744 |
| age | 0.10503099999999999 | 0.028295666666666667 | 0.13332666666666668 | 0.22401133333333334 | 0.08147900000000001 | 0.029367333333333332 | 0.11084633333333334 | 0.21201599999999998 | 1.2890560757986718 | 0.9635082063971306 | 1.2028062873828334 | 1.056577491006968 |
| name_email | 0.176049 | 0.019003 | 0.195052 | 24.200944000000003 | 0.06833733333333332 | 0.03618433333333333 | 0.10452166666666667 | 0.172516 | 2.576176028720271 | 0.5251720357797574 | 1.8661393969352447 | 140.2823158431682 |
| name_age | 0.149232 | 0.02724666666666667 | 0.17647866666666667 | 18.97560866666667 | 0.08749033333333334 | 0.013404666666666667 | 0.100895 | 0.164223 | 1.70569701033638 | 2.0326254538220523 | 1.7491319358408908 | 115.54781404959517 |
| name_email_age | 0.164088 | 0.023389000000000004 | 0.187477 | 19.053912 | 0.09993 | 0.009172333333333333 | 0.10910233333333334 | 0.1806483333333333 | 1.6420294205944161 | 2.5499509394192685 | 1.7183592162709627 | 105.47516076354614 |
| name_age_email | 0.16347633333333333 | 0.047009999999999996 | 0.21048633333333333 | 24.41242766666667 | 0.08065266666666666 | 0.024000333333333335 | 0.104653 | 0.18292300000000003 | 2.0269178948412536 | 1.9587227955167286 | 2.011278542739657 | 133.4573982859819 |
| email_name | 0.17966766666666667 | 0.012885 | 0.19255266666666668 | 22.417591666666667 | 0.07405633333333334 | 0.026322 | 0.10037833333333333 | 0.17567033333333334 | 2.42609454964464 | 0.48951447458399816 | 1.9182692148039917 | 127.61171019200737 |
| email_age | 0.15613133333333332 | 0.028058666666666666 | 0.18419 | 19.154373333333336 | 0.08351633333333335 | 0.016311000000000003 | 0.09982733333333334 | 0.173489 | 1.8694706424691374 | 1.7202297018372057 | 1.8450858482312793 | 110.40684615931463 |
| email_name_age | 0.15354833333333334 | 0.026660666666666666 | 0.18020899999999998 | 18.98274566666667 | 0.07996633333333333 | 0.02410633333333333 | 0.10407266666666666 | 0.176481 | 1.9201622349405376 | 1.1059610890637317 | 1.7315689678365755 | 107.5625459209018 |
| email_age_name | 0.149717 | 0.038108 | 0.187825 | 22.171620666666666 | 0.084615 | 0.019504 | 0.104119 | 0.175933 | 1.7693907699580451 | 1.9538556193601313 | 1.8039454854541437 | 126.02309212408511 |
| age_name | 0.148166 | 0.03416533333333333 | 0.18233133333333332 | 22.189705333333336 | 0.07397966666666667 | 0.025941000000000002 | 0.09992066666666666 | 0.166651 | 2.0027935603927203 | 1.3170399496292868 | 1.8247609770417865 | 133.15074817032803 |
| age_email | 0.15577466666666667 | 0.03964033333333333 | 0.19541499999999998 | 24.123951 | 0.07083433333333333 | 0.029519666666666666 | 0.100354 | 0.16856866666666667 | 2.199140718013393 | 1.342844883072302 | 1.9472567112422023 | 143.11052864707955 |
| age_name_email | 0.16282333333333332 | 0.039232666666666666 | 0.20205599999999999 | 24.318613999999997 | 0.091434 | 0.013128 | 0.104562 | 0.17850233333333332 | 1.780774474848889 | 2.9884724761324395 | 1.9324037413209385 | 136.23695301835457 |
| age_email_name | 0.14960533333333334 | 0.05019233333333334 | 0.19979766666666668 | 22.528416333333336 | 0.063063 | 0.04117766666666667 | 0.10424066666666666 | 0.17867733333333333 | 2.3723155151726583 | 1.21892125990626 | 1.9166959791763933 | 126.08435503850518 |

各項目の比較値を平均すると以下です。

| user | system | total | real |
| --- | --- | --- | --- |
| 1.8890300655510075 | 1.6020634911384024 | 1.7630059872271717 | 109.37265813495286 |

-> `real`を抜くと**約75%**の性能向上が確認できました。


### 2. インデックスなし VS Whereに沿った複合インデックスを付与
|  | インデックスなし |  |  |  | インデックスあり |  |  |  | indexなし / インデックスあり |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 項目名/区分 | user | system | total | real | user | system | total | real | user | system | total | real |
| name | 0.119977 | 0.05756 | 0.17753699999999997 | 12.037523 | 0.09323133333333333 | 0.045049 | 0.13828033333333334 | 0.21919033333333335 | 1.286874226833611 | 1.2777198162001377 | 1.2838919007523362 | 54.91812899291483 |
| email | 0.13663166666666668 | 0.030953000000000005 | 0.1675846666666667 | 11.741430999999999 | 0.08450400000000001 | 0.03976133333333333 | 0.12426533333333334 | 0.203291 | 1.6168662627410142 | 0.7784698702256801 | 1.3486035257889035 | 57.756767392555496 |
| age | 0.10503099999999999 | 0.028295666666666667 | 0.13332666666666668 | 0.22401133333333334 | 0.09956066666666667 | 0.019741333333333333 | 0.119302 | 0.231119 | 1.0549447238199823 | 1.4333209509658247 | 1.1175560063256833 | 0.9692467228282112 |
| name_email | 0.176049 | 0.019003 | 0.195052 | 24.200944000000003 | 0.088985 | 0.024878333333333336 | 0.11386333333333333 | 0.202157 | 1.9784120919256056 | 0.7638373417297514 | 1.7130360959044468 | 119.7136087298486 |
| name_age | 0.149232 | 0.02724666666666667 | 0.17647866666666667 | 18.97560866666667 | 0.08737033333333333 | 0.025171 | 0.11254133333333333 | 0.19444766666666666 | 1.7080397236285392 | 1.08246262232993 | 1.568123119209535 | 97.58722741166005 |
| name_email_age | 0.164088 | 0.023389000000000004 | 0.187477 | 19.053912 | 0.10206966666666667 | 0.022748 | 0.12481766666666666 | 0.23230866666666664 | 1.60760787566662 | 1.0281783013891332 | 1.5020069274381567 | 82.01980698094204 |
| name_age_email | 0.16347633333333333 | 0.047009999999999996 | 0.21048633333333333 | 24.41242766666667 | 0.09404933333333333 | 0.034511 | 0.12856033333333333 | 0.23657466666666668 | 1.738197683485263 | 1.3621743791834486 | 1.6372572151596787 | 103.19121658560229 |
| email_name | 0.17966766666666667 | 0.012885 | 0.19255266666666668 | 22.417591666666667 | 0.108145 | 0.016540666666666665 | 0.12468566666666665 | 0.21546833333333335 | 1.661358977915453 | 0.7789891580347428 | 1.544304744998757 | 104.04123575776795 |
| email_age | 0.15613133333333332 | 0.028058666666666666 | 0.18419 | 19.154373333333336 | 0.086296 | 0.035950666666666665 | 0.12224666666666667 | 0.21367666666666665 | 1.8092534223293468 | 0.7804769498942996 | 1.506707749359219 | 89.6418576353681 |
| email_name_age | 0.15354833333333334 | 0.026660666666666666 | 0.18020899999999998 | 18.98274566666667 | 0.094124 | 0.03335733333333333 | 0.12748133333333334 | 0.24030166666666666 | 1.6313409261541514 | 0.7992445439283716 | 1.4136108815931219 | 78.9954806805335 |
| email_age_name | 0.149717 | 0.038108 | 0.187825 | 22.171620666666666 | 0.11526033333333334 | 0.015042333333333333 | 0.13030266666666665 | 0.241448 | 1.298946442979805 | 2.5333835619473932 | 1.4414516970745035 | 91.82772550059087 |
| age_name | 0.148166 | 0.03416533333333333 | 0.18233133333333332 | 22.189705333333336 | 0.09018 | 0.034354 | 0.12453399999999999 | 0.2133263333333333 | 1.6430028831226435 | 0.9945081601366167 | 1.4641088645135731 | 104.01765682936474 |
| age_email | 0.15577466666666667 | 0.03964033333333333 | 0.19541499999999998 | 24.123951 | 0.10210933333333333 | 0.022233 | 0.12434233333333333 | 0.21774833333333335 | 1.5255673656995117 | 1.7829502691194772 | 1.5715886517597921 | 110.78822340775666 |
| age_name_email | 0.16282333333333332 | 0.039232666666666666 | 0.20205599999999999 | 24.318613999999997 | 0.095568 | 0.03349866666666667 | 0.12906666666666666 | 0.23559866666666665 | 1.7037432334393658 | 1.1711709918802737 | 1.5655165289256199 | 103.22050775612765 |
| age_email_name | 0.14960533333333334 | 0.05019233333333334 | 0.19979766666666668 | 22.528416333333336 | 0.08135833333333332 | 0.048427 | 0.12978533333333334 | 0.23627933333333337 | 1.8388446174331663 | 1.0364534935745213 | 1.5394471897184068 | 95.34653757275993 |

各項目の比較値を平均すると以下です。

| user | system | total | real |
| --- | --- | --- | --- |
| 1.6068666971449386 | 1.1735560273693069 | 1.4811474065681154 | 86.26901519710808 |

-> `real`を抜くと**約42%**の性能向上が確認できました。


# 所感
各カラムにそれぞれインデックスを付与するパターンで、75%の性能向上を確認することが出来ました。
ただ、複合インデックスが`Where`の順に設定すれば爆速になると聞いていたので、各カラムのインデックス付与よりも性能が向上しないのは残念でした。。。
インデックスなしの場合よりも性能自体は向上しているので、インデックスが効いていないことはないと思うのですが。。。
（恐らくインデックスの貼り方が間違っているだけかと思うので、引き続き調査を行う必要がありそうです）

また、今回の調査でインデックスを付けたり、外したりする方法も学ぶことが出来ました！
RailsからDBを扱うことに少しは慣れてきたのではないかと思います！

# （おまけ）各項目の計測ログ
今回の調査の手順を各パターンごとにログとして残しました。
MySQLでのインデックスの確認等も含めて残しているので、かなり長いです。。。

<details><summary>ログ詳細</summary><div>

## 1. インデックスなし
インデックスなしの場合はベンチマーク計測のみを行います。

### 1-1. 結果
3回のベンチマークから平均を取得し比較対象の値とします。

| 実行回数 | 1回目 |  |  |  | 2回目 |  |  |  | 3回目 |  |  |  | 平均 |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 項目名/区分 | user | system | total | real | user | system | total | real | user | system | total | real | user | system | total | real |
| name | 0.184796 | 0.020163 | 0.204959 | 12.403299 | 0.096084 | 0.070318 | 0.166402 | 11.937761 | 0.079051 | 0.082199 | 0.16125 | 11.771509 | 0.119977 | 0.05756 | 0.17753699999999997 | 12.037523 |
| email | 0.125404 | 0.053447 | 0.178851 | 11.713384 | 0.140241 | 0.020188 | 0.160429 | 11.705146 | 0.14425 | 0.019224 | 0.163474 | 11.805763 | 0.13663166666666668 | 0.030953000000000005 | 0.1675846666666667 | 11.741430999999999 |
| age | 0.095059 | 0.033478 | 0.128537 | 0.201307 | 0.105612 | 0.025862 | 0.131474 | 0.231714 | 0.114422 | 0.025547 | 0.139969 | 0.239013 | 0.10503099999999999 | 0.028295666666666667 | 0.13332666666666668 | 0.22401133333333334 |
| name_email | 0.182493 | 0.012706 | 0.195199 | 24.216515 | 0.174361 | 0.018819 | 0.19318 | 24.165059 | 0.171293 | 0.025484 | 0.196777 | 24.221258 | 0.176049 | 0.019003 | 0.195052 | 24.200944000000003 |
| name_age | 0.13965 | 0.037509 | 0.177159 | 18.989737 | 0.158557 | 0.011399 | 0.169956 | 18.849954 | 0.149489 | 0.032832 | 0.182321 | 19.087135 | 0.149232 | 0.02724666666666667 | 0.17647866666666667 | 18.97560866666667 |
| name_email_age | 0.134688 | 0.046022 | 0.18071 | 19.076824 | 0.150945 | 0.023451 | 0.174396 | 18.932894 | 0.206631 | 0.000694 | 0.207325 | 19.152018 | 0.164088 | 0.023389000000000004 | 0.187477 | 19.053912 |
| name_age_email | 0.15958 | 0.042227 | 0.201807 | 24.222543 | 0.141402 | 0.061891 | 0.203293 | 24.272176 | 0.189447 | 0.036912 | 0.226359 | 24.742564 | 0.16347633333333333 | 0.047009999999999996 | 0.21048633333333333 | 24.41242766666667 |
| email_name | 0.173105 | 0.007625 | 0.18073 | 22.197503 | 0.184156 | 0.000951 | 0.185107 | 22.20186 | 0.181742 | 0.030079 | 0.211821 | 22.853412 | 0.17966766666666667 | 0.012885 | 0.19255266666666668 | 22.417591666666667 |
| email_age | 0.149757 | 0.022741 | 0.172498 | 18.953898 | 0.155153 | 0.017408 | 0.172561 | 18.902814 | 0.163484 | 0.044027 | 0.207511 | 19.606408 | 0.15613133333333332 | 0.028058666666666666 | 0.18419 | 19.154373333333336 |
| email_name_age | 0.134962 | 0.041572 | 0.176534 | 19.01526 | 0.153223 | 0.026015 | 0.179238 | 18.868271 | 0.17246 | 0.012395 | 0.184855 | 19.064706 | 0.15354833333333334 | 0.026660666666666666 | 0.18020899999999998 | 18.98274566666667 |
| email_age_name | 0.170493 | 0.014796 | 0.185289 | 22.213629 | 0.129427 | 0.060045 | 0.189472 | 22.136256 | 0.149231 | 0.039483 | 0.188714 | 22.164977 | 0.149717 | 0.038108 | 0.187825 | 22.171620666666666 |
| age_name | 0.160732 | 0.020446 | 0.181178 | 22.229864 | 0.144351 | 0.038095 | 0.182446 | 22.16279 | 0.139415 | 0.043955 | 0.18337 | 22.176462 | 0.148166 | 0.03416533333333333 | 0.18233133333333332 | 22.189705333333336 |
| age_email | 0.156309 | 0.038236 | 0.194545 | 24.15738 | 0.152898 | 0.044281 | 0.197179 | 24.144195 | 0.158117 | 0.036404 | 0.194521 | 24.070278 | 0.15577466666666667 | 0.03964033333333333 | 0.19541499999999998 | 24.123951 |
| age_name_email | 0.184938 | 0.018403 | 0.203341 | 24.471656 | 0.135366 | 0.065777 | 0.201143 | 24.153038 | 0.168166 | 0.033518 | 0.201684 | 24.331148 | 0.16282333333333332 | 0.039232666666666666 | 0.20205599999999999 | 24.318613999999997 |
| age_email_name | 0.145016 | 0.052333 | 0.197349 | 22.756954 | 0.134883 | 0.054077 | 0.18896 | 22.179658 | 0.168917 | 0.044167 | 0.213084 | 22.648637 | 0.14960533333333334 | 0.05019233333333334 | 0.19979766666666668 | 22.528416333333336 |


## 2. インデックスあり（各カラムにインデックスを付与）
### 2-1. マイグレーションファイルの作成
```bash:ターミナル
$ rails g migration add_index_user_each_columns
Running via Spring preloader in process 190
      invoke  active_record
      create    db/migrate/20220110125827_add_index_user_each_columns.rb
```
```ruby:db/migrate/20220110125827_add_index_user_each_columns.rb
class AddIndexUserEachColumns < ActiveRecord::Migration[6.1]
  def change
    add_index :users, :name
    add_index :users, :email
    add_index :users, :age
  end
end
```

### 2-2. マイグレーションファイルの適用とインデックス確認

```bash:ターミナル
$ rails db:migrate
Running via Spring preloader in process 155
== 20220110125827 AddIndexUserEachColumns: migrating ==========================
-- add_index(:users, :name)
   -> 1.3526s
-- add_index(:users, :email)
   -> 1.8436s
-- add_index(:users, :age)
   -> 0.7364s
== 20220110125827 AddIndexUserEachColumns: migrated (3.9329s) ================
```

mysqlでインデックスが適用されているか確認します。

```bash:ターミナル
mysql> use considerable_db_select_development;
mysql> show index from users;
+-------+------------+----------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name             | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+----------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| users |          0 | PRIMARY              |            1 | id          | A         |       94032 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_name  |            1 | name        | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_email |            1 | email       | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_age   |            1 | age         | A         |         192 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+-------+------------+----------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
4 rows in set (0.00 sec)
```

### 2-3. 結果

| 実行回数 | 1回目 |  |  |  | 2回目 |  |  |  | 3回目 |  |  |  | 平均 |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 項目名/区分 | user | system | total | real | user | system | total | real | user | system | total | real | user | system | total | real |
| name | 0.101244 | 0.052994 | 0.154238 | 0.22802 | 0.095663 | 0.012477 | 0.10814 | 0.157432 | 0.080849 | 0.025216 | 0.106065 | 0.170013 | 0.09258533333333334 | 0.030229000000000002 | 0.12281433333333334 | 0.185155 |
| email | 0.109867 | 0.009012 | 0.118879 | 0.18326 | 0.087584 | 0.015471 | 0.103055 | 0.15234 | 0.08338 | 0.022894 | 0.106274 | 0.17071 | 0.09361033333333334 | 0.015792333333333335 | 0.10940266666666666 | 0.16877 |
| age | 0.09528 | 0.029398 | 0.124678 | 0.224295 | 0.057978 | 0.046727 | 0.104705 | 0.213601 | 0.091179 | 0.011977 | 0.103156 | 0.198152 | 0.08147900000000001 | 0.029367333333333332 | 0.11084633333333334 | 0.21201599999999998 |
| name_email | 0.077991 | 0.035071 | 0.113062 | 0.175443 | 0.062348 | 0.038042 | 0.10039 | 0.172885 | 0.064673 | 0.03544 | 0.100113 | 0.16922 | 0.06833733333333332 | 0.03618433333333333 | 0.10452166666666667 | 0.172516 |
| name_age | 0.102032 | 0 | 0.102032 | 0.154649 | 0.071336 | 0.02884 | 0.100176 | 0.169989 | 0.089103 | 0.011374 | 0.100477 | 0.168031 | 0.08749033333333334 | 0.013404666666666667 | 0.100895 | 0.164223 |
| name_email_age | 0.111156 | 0.010722 | 0.121878 | 0.183617 | 0.088124 | 0.013819 | 0.101943 | 0.18144 | 0.10051 | 0.002976 | 0.103486 | 0.176888 | 0.09993 | 0.009172333333333333 | 0.10910233333333334 | 0.1806483333333333 |
| name_age_email | 0.101618 | 0.004041 | 0.105659 | 0.185949 | 0.06131 | 0.042637 | 0.103947 | 0.180886 | 0.07903 | 0.025323 | 0.104353 | 0.181934 | 0.08065266666666666 | 0.024000333333333335 | 0.104653 | 0.18292300000000003 |
| email_name | 0.086675 | 0.012576 | 0.099251 | 0.173273 | 0.086501 | 0.013465 | 0.099966 | 0.172219 | 0.048993 | 0.052925 | 0.101918 | 0.181519 | 0.07405633333333334 | 0.026322 | 0.10037833333333333 | 0.17567033333333334 |
| email_age | 0.093451 | 0.007663 | 0.101114 | 0.173296 | 0.096709 | 0.002186 | 0.098895 | 0.17418 | 0.060389 | 0.039084 | 0.099473 | 0.172991 | 0.08351633333333335 | 0.016311000000000003 | 0.09982733333333334 | 0.173489 |
| email_name_age | 0.082012 | 0.023237 | 0.105249 | 0.164651 | 0.088585 | 0.013772 | 0.102357 | 0.180251 | 0.069302 | 0.03531 | 0.104612 | 0.184541 | 0.07996633333333333 | 0.02410633333333333 | 0.10407266666666666 | 0.176481 |
| email_age_name | 0.08192 | 0.021129 | 0.103049 | 0.163807 | 0.08511 | 0.018672 | 0.103782 | 0.180851 | 0.086815 | 0.018711 | 0.105526 | 0.183141 | 0.084615 | 0.019504 | 0.104119 | 0.175933 |
| age_name | 0.095358 | 0.004731 | 0.100089 | 0.154133 | 0.038377 | 0.061667 | 0.100044 | 0.177529 | 0.088204 | 0.011425 | 0.099629 | 0.168291 | 0.07397966666666667 | 0.025941000000000002 | 0.09992066666666666 | 0.166651 |
| age_email | 0.057332 | 0.044002 | 0.101334 | 0.158317 | 0.066989 | 0.033157 | 0.100146 | 0.172823 | 0.088182 | 0.0114 | 0.099582 | 0.174566 | 0.07083433333333333 | 0.029519666666666666 | 0.100354 | 0.16856866666666667 |
| age_name_email | 0.091743 | 0.011442 | 0.103185 | 0.162566 | 0.087681 | 0.01675 | 0.104431 | 0.180981 | 0.094878 | 0.011192 | 0.10607 | 0.19196 | 0.091434 | 0.013128 | 0.104562 | 0.17850233333333332 |
| age_email_name | 0.060333 | 0.048183 | 0.108516 | 0.18156 | 0.07232 | 0.029589 | 0.101909 | 0.176594 | 0.056536 | 0.045761 | 0.102297 | 0.177878 | 0.063063 | 0.04117766666666667 | 0.10424066666666666 | 0.17867733333333333 |

### 2-4. インデックスを削除
次の計測を行うため、付与したインデックスを削除します。

```bash:ターミナル
$ rails g migration remove_index_user_each_columns
Running via Spring preloader in process 197
      invoke  active_record
      create    db/migrate/20220111144123_remove_index_user_each_columns.rb
```

```ruby:db/migrate/20220111144123_remove_index_user_each_columns.rb
class RemoveIndexUserEachColumns < ActiveRecord::Migration[6.1]
  def change
    remove_index :users, :name
    remove_index :users, :email
    remove_index :users, :age
  end
end
```

```bash:ターミナル
$ rails db:migrate
Running via Spring preloader in process 206
== 20220111144123 RemoveIndexUserEachColumns: migrating =======================
-- remove_index(:users, :name)
   -> 0.0278s
-- remove_index(:users, :email)
   -> 0.0246s
-- remove_index(:users, :age)
   -> 0.0269s
== 20220111144123 RemoveIndexUserEachColumns: migrated (0.0796s) ==============
```

mysqlでインデックスが削除されているか確認します。

```bash:ターミナル
mysql> use considerable_db_select_development;
mysql> desc users;
+------------+------------------+------+-----+---------+----------------+
| Field      | Type             | Null | Key | Default | Extra          |
+------------+------------------+------+-----+---------+----------------+
| id         | bigint           | NO   | PRI | NULL    | auto_increment |
| name       | varchar(255)     | YES  |     | NULL    |                |
| email      | varchar(255)     | YES  |     | NULL    |                |
| age        | tinyint unsigned | YES  |     | NULL    |                |
| created_at | datetime(6)      | NO   |     | NULL    |                |
| updated_at | datetime(6)      | NO   |     | NULL    |                |
+------------+------------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
```


## 3. インデックスあり（Whereに沿った複合インデックスを付与）
### 3-1. マイグレーションファイルの作成

```bash:ターミナル
rails g migration add_index_user_multiple_columns
Running via Spring preloader in process 215
      invoke  active_record
      create    db/migrate/20220112144927_add_index_user_multiple_columns.rb
```

```ruby:db/migrate/20220112144927_add_index_user_multiple_columns.rb
class AddIndexUserMultipleColumns < ActiveRecord::Migration[6.1]
  def change
    add_index :users, [:age, :name, :email]
    add_index :users, [:name, :email, :age]
    add_index :users, [:email, :age, :name]
    add_index :users, [:age, :email, :name]
    add_index :users, [:email, :name, :age]
    add_index :users, [:name, :age, :email]
  end
end
```

### 3-2. マイグレーションファイルの適用とインデックス確認

```bash:ターミナル
rails db:migrate
Running via Spring preloader in process 304
== 20220112152642 AddIndexUserMultipleColumns: migrating =====================
-- add_index(:users, [:age, :name, :email])
   -> 2.1185s
-- add_index(:users, [:name, :email, :age])
   -> 2.0313s
-- add_index(:users, [:email, :age, :name])
   -> 2.2623s
-- add_index(:users, [:age, :email, :name])
   -> 2.2616s
-- add_index(:users, [:email, :name, :age])
   -> 2.0837s
-- add_index(:users, [:name, :age, :email])
   -> 2.2160s
== 20220112152642 AddIndexUserMultipleColumns: migrated (12.9740s) ===========
```

mysqlでインデックスが付与されているか確認します。

```bash:ターミナル
mysql> show index from users;
+-------+------------+---------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name                              | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+---------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| users |          0 | PRIMARY                               |            1 | id          | A         |       94032 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_age_and_name_and_email |            1 | age         | A         |         202 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_age_and_name_and_email |            2 | name        | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_age_and_name_and_email |            3 | email       | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_name_and_email_and_age |            1 | name        | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_name_and_email_and_age |            2 | email       | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_name_and_email_and_age |            3 | age         | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_email_and_age_and_name |            1 | email       | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_email_and_age_and_name |            2 | age         | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_email_and_age_and_name |            3 | name        | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_age_and_email_and_name |            1 | age         | A         |         191 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_age_and_email_and_name |            2 | email       | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_age_and_email_and_name |            3 | name        | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_email_and_name_and_age |            1 | email       | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_email_and_name_and_age |            2 | name        | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_email_and_name_and_age |            3 | age         | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_name_and_age_and_email |            1 | name        | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_name_and_age_and_email |            2 | age         | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | index_users_on_name_and_age_and_email |            3 | email       | A         |       99826 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+-------+------------+---------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
19 rows in set (0.00 sec)
```

### 3-3. 結果
| 実行回数 | 1回目 |  |  |  | 2回目 |  |  |  | 3回目 |  |  |  | 平均 |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 項目名/区分 | user | system | total | real | user | system | total | real | user | system | total | real | user | system | total | real |
| name | 0.142947 | 0.0262 | 0.169147 | 0.265678 | 0.118934 | 0.017906 | 0.13684 | 0.210385 | 0.017813 | 0.091041 | 0.108854 | 0.181508 | 0.09323133333333333 | 0.045049 | 0.13828033333333334 | 0.21919033333333335 |
| email | 0.110352 | 0.032993 | 0.143345 | 0.236412 | 0.053 | 0.071738 | 0.124738 | 0.196106 | 0.09016 | 0.014553 | 0.104713 | 0.177355 | 0.08450400000000001 | 0.03976133333333333 | 0.12426533333333334 | 0.203291 |
| age | 0.140528 | 0.002601 | 0.143129 | 0.26415 | 0.072299 | 0.035691 | 0.10799 | 0.221997 | 0.085855 | 0.020932 | 0.106787 | 0.20721 | 0.09956066666666667 | 0.019741333333333333 | 0.119302 | 0.231119 |
| name_email | 0.082666 | 0.057177 | 0.139843 | 0.240555 | 0.083477 | 0.017458 | 0.100935 | 0.183504 | 0.100812 | 0 | 0.100812 | 0.182412 | 0.088985 | 0.024878333333333336 | 0.11386333333333333 | 0.202157 |
| name_age | 0.095453 | 0.025902 | 0.121355 | 0.205616 | 0.060621 | 0.042125 | 0.102746 | 0.181752 | 0.106037 | 0.007486 | 0.113523 | 0.195975 | 0.08737033333333333 | 0.025171 | 0.11254133333333333 | 0.19444766666666666 |
| name_email_age | 0.096965 | 0.033171 | 0.130136 | 0.243576 | 0.08013 | 0.0229 | 0.10303 | 0.200773 | 0.129114 | 0.012173 | 0.141287 | 0.252577 | 0.10206966666666667 | 0.022748 | 0.12481766666666666 | 0.23230866666666664 |
| name_age_email | 0.118087 | 0.023659 | 0.141746 | 0.255481 | 0.048665 | 0.056811 | 0.105476 | 0.202183 | 0.115396 | 0.023063 | 0.138459 | 0.25206 | 0.09404933333333333 | 0.034511 | 0.12856033333333333 | 0.23657466666666668 |
| email_name | 0.111005 | 0.024605 | 0.13561 | 0.227609 | 0.102973 | 0 | 0.102973 | 0.186023 | 0.110457 | 0.025017 | 0.135474 | 0.232773 | 0.108145 | 0.016540666666666665 | 0.12468566666666665 | 0.21546833333333335 |
| email_age | 0.098197 | 0.030853 | 0.12905 | 0.225754 | 0.068812 | 0.030915 | 0.099727 | 0.181805 | 0.091879 | 0.046084 | 0.137963 | 0.233471 | 0.086296 | 0.035950666666666665 | 0.12224666666666667 | 0.21367666666666665 |
| email_name_age | 0.12836 | 0.009594 | 0.137954 | 0.249308 | 0.072985 | 0.033483 | 0.106468 | 0.223655 | 0.081027 | 0.056995 | 0.138022 | 0.247942 | 0.094124 | 0.03335733333333333 | 0.12748133333333334 | 0.24030166666666666 |
| email_age_name | 0.114365 | 0.022879 | 0.137244 | 0.251138 | 0.10205 | 0.011416 | 0.113466 | 0.223384 | 0.129366 | 0.010832 | 0.140198 | 0.249822 | 0.11526033333333334 | 0.015042333333333333 | 0.13030266666666665 | 0.241448 |
| age_name | 0.089613 | 0.045178 | 0.134791 | 0.227381 | 0.058726 | 0.041303 | 0.100029 | 0.179208 | 0.122201 | 0.016581 | 0.138782 | 0.23339 | 0.09018 | 0.034354 | 0.12453399999999999 | 0.2133263333333333 |
| age_email | 0.108056 | 0.029188 | 0.137244 | 0.2342 | 0.091907 | 0.006874 | 0.098781 | 0.184788 | 0.106365 | 0.030637 | 0.137002 | 0.234257 | 0.10210933333333333 | 0.022233 | 0.12434233333333333 | 0.21774833333333335 |
| age_name_email | 0.134192 | 0.008121 | 0.142313 | 0.253583 | 0.059607 | 0.045487 | 0.105094 | 0.200226 | 0.092905 | 0.046888 | 0.139793 | 0.252987 | 0.095568 | 0.03349866666666667 | 0.12906666666666666 | 0.23559866666666665 |
| age_email_name | 0.069038 | 0.071594 | 0.140632 | 0.252128 | 0.075505 | 0.033088 | 0.108593 | 0.205883 | 0.099532 | 0.040599 | 0.140131 | 0.250827 | 0.08135833333333332 | 0.048427 | 0.12978533333333334 | 0.23627933333333337 |

</div></details>

## 参考にさせていただいた記事
* Ruby
    * ベンチマーク
        * [Ruby でベンチマークを取る方法
](https://qiita.com/scivola/items/c5b2aeaf7d67a9ef310a)
    * irb
        * [自分が書いたRubyプログラムをirb上で読み込む方法
](https://qiita.com/jnchito/items/65129346fa0cd713855f)
    * parallel
        * [自分が書いたRubyプログラムをirb上で読み込む方法
](https://blog.parity-box.com/posts/articles/2021/rails-parallel-seed)
    * index
        * [データベースにindexを張る方法
](https://qiita.com/seiya1121/items/fb074d727c6f40a55f22)
        * [【Rails】DBのカラムにインデックスを付与する/しない場合での速度比較をしてみた
](https://qiita.com/terufumi1122/items/ad01ff599572e6dcfed2)
    * Logger
        * [Rails Consoleで表示されるSQLのログを非表示にする
](https://takagi.blog/hide-sql-log-displayed-in-rails-console/)
* MySQL
    * [MySQLで複合インデックスを作成してみる](https://yk5656.hatenadiary.org/entry/20140205/1392080263)
    * [MySQLで大量のデータを追加してみる](https://yk5656.hatenadiary.org/entry/20140202/1391910335)
    * [MySQLでインデックスが貼られているかを確認するSQL](https://qiita.com/pugiemonn/items/2edf5d7967fb45dd5196)
    * [8.3.9 B ツリーインデックスとハッシュインデックスの比較](https://dev.mysql.com/doc/refman/8.0/ja/index-btree-hash.html)
    * [MySQL：indexの貼り方には要注意。速度低下の原因はインデックスだった。](https://qol-kk.com/wp2/blog/2019/11/14/post-1315/)