主キーとIndexについて整理する

#はじめに
[夏ぼっちカレンダー（仮）](https://qiita.com/pirorirori_n712/items/4dc66870ccd3cc540f68)の一日目の記事です。

主キーとIndexの違いがよく分からなくなるので、
整理しようと思います。
想定しているデータベース管理システムはMySQLです。

記事の中に間違いなどあれば指摘していただけると幸いです。

#主キーとは？
・primary keyとも呼ばれる（primaty keyの訳が主キー）
→ primaryは日本語で「主要の」という意味
・PRIMARY KEY制約をつけられたカラムに入るデータ
・NULL非許容、重複した値を入れることができない
→ テーブル内でのデータを一意に確定させることができる

##主キーは何のために必要？
・多くのデータの中で、データを一意に定めてくれるものがあれば、検索などが簡単になるから

本でいうISBNコードのようなもの、
ISBNコードが分かれば
どの本を指しているのかを世界中の書物から特定することができ、
その書物の情報を取得することができる。
[ISBNとは](https://isbn.jpo.or.jp/index.php/fix__about/fix__about_2/)

##主キーはこうして作られる
・<b>PRIMARY KEY制約</b>を設定して作られたカラムの中のデータが主キーになる

```sql
CREATE TABLE books{
    book_id PRIMARY KEY,//この中に入るデータが主キー
    name VARCHAR(255),
    author VARCHAR(255),
    publication_date DATETIME
};
```
上のCREATE文でできるテーブルに、データを一つ入れたもの↓

| book_id | name | author | publication_date |
|---|---|---|---|
| <b>1</b> | hoge | hogehoge | 2000/01/01 |
book_idカラムに設定されている「1」が主キー

##PRIMARY KEY制約
・PRIMARY KEY制約はRDBで設定できる制約の一つ
以下のものが主な制約[^1]

| 制約の種類 | 説明 |
|---|---|
| PRIMARY KEY制約 | 重複とNULLが許容されない、行がテーブル内で一意であることを確定させる |
| UNIQUE制約 | NULLは許容する、値がテーブル内で一意であることを確定させる |
| CHECK制約 | 指定した条件の値のみが保存されていることを確定させる |
| DEFAULT制約 | 値が指定されないときに保存される値を決め、初期値を確定させる |
| FOREIGN KEY制約（外部キー） | 別テーブルの主キーと参照整合性が保たれていることを確定させる |


上の制約はどれもカラムに入るデータに対する制約である、
一度int型の変数にする！と決めたらその後は
制約にそぐわないデータが入るのを防いでくれる。
（制約という形でデータを確認して予期せぬアクシデントを防ぐ）

PRIMARY KEY制約はテーブルの各カラムを作る際の設定の一つであり、
その制約をつけられたカラムの中のデータが主キーとなる。

###PRIMARY KEY制約の効果
PRIMARY KEY制約の効果は、
「重複とNULLが許容されない、行がテーブル内で一意であることを確定させる」
というもの

行がテーブル内で一意であることを確定させるので
例は以下のようになる。

<b>許容される例</b>

| book_id | name | author | publication_date |
|---|---|---|---|
| 1 | hoge | hogehoge | 2000/01/01 |
| 2 | fuga | fugafuga | 2010/12/25 |
| 3 | piyo | piyopiyo | 2000/01/01 |

PRIMARY KEY制約をつけられた
book_idカラムの中に入っているデータが
それぞれ異なっているので
book_idの値を指定すれば
全てのデータの中で必ずどれか<b>一つ</b>を指していることになる

つまり「<b>行がテーブル内で一意であることを確定させ」ている</b>ことになる


逆に以下のような例は入力の段階で弾かれる

<b>許容されない例</b>

| book_id | name | author | publication_date |
|---|---|---|---|
| 1 | hoge | hogehoge | 2000/01/01 |
| 2 | fuga | fugafuga | 2010/12/25 |
| 1 | piyo | piyopiyo | 2000/01/01 |

PRIMARY KEY制約をつけられた
book_idカラムの中に入っているデータに
<b>重複がある</b>ので
book_idの値を指定しても
全てのデータの中でどれか一つを指すことが<b>できない</b>

つまり「<b>行がテーブル内で一意であることを確定させ」ることができていない</b>

このようなデータは、データを入れようとしたときにエラーになる

##主キーまとめ
・PRIMATY KEY制約をつけられたカラムに入るデータ
・テーブル内でのデータを一意に確定させることができる

#Indexとは？
・日本語では「索引」という意味
・テーブルからデータを取り出すためのRDBMSの仕組み
・Indexを適切に作成し、検索時に使用することによってクエリを高速化することができる

##Indexは何のために必要？
・検索を速くするため

##Indexはこうして作られる
例えば、先に使用したbooksテーブルの中にデータが50万件くらい入っているとする。
そのデータの中から、特定のauthorのデータだけを抜き出したいとなった。
（それぞれのauthorのデータは50件くらい。）

単純に以下のクエリを使用すると時間がかかる。

```sql
SELECT * FROM books WHERE author = "piyo";
```
50万件のデータをフルスキャンして、
authorが合致するデータかどうかを
一つ一つ確認していくのでとても時間がかかる。

そこでauthorカラムにIndexを張る

```sql
CREATE INDEX author_idx ON books(author);
```

そうすると
対象のカラムのデータを取り出して、
高速に検索できるように昇順に並び替えたものが作成される

| book_id | author |
|---|---|
| 1 | hogehoge |
| 2 | fugafuga |
| 1 | piyopiyo |

これによって検索を速くすることができる。

#主キーとIndexの違い
・主キーは、「テーブル内でのデータを一意に確定させる」もの
・Indexは「検索」を速くするためのもの

作り方も目的も全く違うということが整理できました。

#なぜ主キーとIndexを混同してしまうのか？
主キーを作成すると自動的にIndexが張られる、かつ
whereやjoinする際に
主キーを使うことが多いので、
主キーが検索に使用される→検索を早くするためのIndexと混同する
ということが起こるのではないかなと思います。

#参考
曽根壮大著『失敗から学ぶRDBの正しい歩き方』株式会社技術評論社、2019年
西沢夢路『基礎からのMySQL 第3版』ソフトバンククリエイティブ株式会社、2017年

[SQLの制約の種類とその指定方法](https://qiita.com/Uejun/items/de02b78adbc54868d40d)
[整合性制約のタイプ](https://www.shift-the-oracle.com/constraint/)

[主キーとインデックスの違いについて](https://okwave.jp/qa/q4401156.html)
[外部キー(foreign key)を作成するとインデックスもついてくる](http://kwski.net/mysql/602/)
[プライマリキーとインデックスの違い](https://bi-na.hatenadiary.org/entry/20120218/1329530104)
[ソーシャルゲーム開発者なら知っておきたい MySQL INDEX + EXPLAIN入門](http://www.infiniteloop.co.jp/blog/2011/03/mysql-index-explain/)

[MySQLでインデックスを貼る時に読みたいページまとめ(初心者向け）](https://qiita.com/C058/items/1c9c57f634ebf54d99bb)
[MySQLのインデックスの効果を理解する](https://memo.sugyan.com/entry/20100926/1285508863)
[MySQL初級者を脱するために勉強してること -INDEX編-](https://qiita.com/kkyouhei/items/e3502ef632c48d94541d)
[インデックスの意味とメリット・デメリット](https://www.dbonline.jp/sqlite/index/index1.html)



[^1]: 曽根壮大著『失敗から学ぶRDBの正しい歩き方』株式会社技術評論社、2019年、2ページ