Postgresql 極小テーブル同士の結合はindexを使わないほうが早いのか？

# ひとりごと
 DB初心者がpostgresqlを学んでいこうと思い、メモ代わりに投稿してみます。
 
# はじめに
 DBのお勉強をしていて、実行計画を理解しようと、とりあえずなんでも
 ```ruby:qiita.rb
Explain Analyz '****'
```
してます。

そこで、ふと小さいテーブルはシーケンシャルスキャン（テーブルを全部読み込む！）の方が早い。と思っていたが、小さいテーブル同士の結合でもそうか？と試したくなったので、やってみました。

# 対象テーブル

たったこれだけ。

- employees（従業員）テーブル
    - employee_id:主キー（btree indexキー）
    - department_id:外部キー

    | employee_id | name   | department_id |
    |:-----------:|:------:|:-------------:|
    | 1           | wiwa   | 5             |
    | 2           | niwa   | 3             |
    | 3           | iwa    | 4             |
    | 4           | yonwa  | 7             |
    | 5           | gowa   | 8             |
    | 6           | rokuwa | 1             |

<br>

- departments（部署）テーブル（btree indexキー）
    - department_id:主キー

    | department_id | department_name | locale |
    |:-:|:-:|:-:|
    | 1 | 営業 | 東京 |
    | 2 | 相1生産管理 | 福島 |
    | 3 | 相2生産管理 | 福島 |
    | 4 | 東京生産管理 | 東京 |
    | 5 | 広島1生産管理 | 広島 |
    | 6 | 広島2生産管理 | 福島 |
    | 7 | 財務 | 東京 |
    | 8 | 人事 | 東京 |

# 検証方法
employeesとdepartmentsを結合するクエリを発行し、以下を比較する
- indexをONにした時
- indexをOFにした時

# indexをONにした時
 ```ruby:qiita.rb
explain analyze

select 
    *
from
    production.employees as B
join
    production.departments as A
on
    A.department_id = B.department_id
```
<br>

- 実行計画
> "QUERY PLAN"
"Nested Loop  (cost=0.16..54.86 rows=1180 width=62) (actual time=0.179..0.200 rows=6 loops=1)"
"  ->  Seq Scan on employees b  (cost=0.00..21.80 rows=1180 width=41) (actual time=0.078..0.080 rows=6 loops=1)"
"  ->  Memoize  (cost=0.16..0.22 rows=1 width=21) (actual time=0.016..0.016 rows=1 loops=6)"
"        Cache Key: b.department_id"
"        Cache Mode: logical"
"        Hits: 0  Misses: 6  Evictions: 0  Overflows: 0  Memory Usage: 1kB"
"        ->  Index Scan using departments_pkey on departments a  (cost=0.15..0.21 rows=1 width=21) (actual time=0.011..0.011 rows=1 loops=6)"
"              Index Cond: (department_id = b.department_id)"
"Planning Time: 0.591 ms"
"Execution Time: 0.336 ms"

# indexをOFFにした時

```ruby:qiita.rb
SET enable_indexscan = off;

explain analyze

select 
    *
from
    production.employees as B
join
    production.departments as A
on
    A.department_id = B.department_id
```
<br>

- 実行計画

>"QUERY PLAN"
"Hash Join  (cost=47.35..72.26 rows=1180 width=62) (actual time=0.624..0.641 rows=6 loops=1)"
"  Hash Cond: (b.department_id = a.department_id)"
"  ->  Seq Scan on employees b  (cost=0.00..21.80 rows=1180 width=41) (actual time=0.153..0.156 rows=6 loops=1)"
"  ->  Hash  (cost=26.60..26.60 rows=1660 width=21) (actual time=0.159..0.160 rows=8 loops=1)"
"        Buckets: 2048  Batches: 1  Memory Usage: 17kB"
"        ->  Seq Scan on departments a  (cost=0.00..26.60 rows=1660 width=21) (actual time=0.044..0.050 rows=8 loops=1)"
"Planning Time: 0.977 ms"
"Execution Time: 1.249 ms"

# 推測
| パターン | 実績（Execution Time） | 
|:-:|:-:|
| index ON |0.336 | 
| index OFF | 1.249 |

ということで、indexを使った方が早かったです（予想外

実行計画を見るにシーケンシャルスキャン（index OFFの場合）だと
- departmentsテーブルにHashテーブルを作成しているが、これが遅い
- 遅い割に、テーブルのレコード数が少ないので、結合する際にあまり活用できない

こんな感じが遅い理由かな？と思います。
おとなしく、インデックススキャン（index onの場合）しとけですね
（おそらく以下のフロー
- employeesを全件スキャン
- department_idをもとにdepartmentテーブルをインデックススキャンして結合

# ひとりごと
以上です。ご指摘等あれば、いただければと:point_up: