インデックス・トランザクション・デッドロックをざっくり解説してみる

# はじめに
プログラミングをRailsから始めた僕なのですが、Railsのアクティブレコード（Active Record）の優しさに甘やかされDBのことをなんとなくしか理解していませんでした。。。（Railsをディスりたいわけじゃなく、単純に）
インデックスとかトランザクションとか、、、なんとなく言葉では知ってたり雰囲気は知ってるけど、正直なにしてるかよくわからん、、、

と思っていたのですが、最近割と就活をちゃんとやっているとその辺の基礎のことをめちゃめちゃ聞かれることが多くて、その質問をされるたびにめちゃめちゃ萎えるので一気に勉強して備忘録としても残しちゃおう！っていうのがこの記事が生産された理由となっておりますw


# インデックス（早く検索できるようにするやつ）
## ざっくりインデックスって？
イメージの広辞苑の目次みたいなものだと思ってもらえるといいと思います！
例えば辞書で「プログラミング」って調べようと思った時に辞書を１ページ目から引かないと思います
多分「は」の行まで飛ばしてそこからめくっていくと思うんですけど、ざっくりとはそんな感じです

じゃあ、カラムの全てにインデックス貼ったほうがいいんじゃないの?って言う割と当たり前の疑問があると思うのですがそれはダメです。
それについては↓で説明します。

## ちゃんとインデックスを考える
| ID |  name|age|
|----|----|----|
| 1  |kimura|20|
| 2  |anndo|35|
| 3  |sato|24|
| 4  |nakamuura|18|
例えば上記のようなUserテーブルがあるとします。
そこでUserのnameカラムにインデックスを貼ると以下のようなテーブルが通常のテーブルとは**別に作成されます。**

| ID |  name|
|----|----|
| 2  |anndo|
| 1  |kimura|
| 4  |nakamura|
| 3  |sato|

もともとあったUserテーブルとは異なり、カラムがIDとNameのみとなり、nameカラムの値も昇順（a→zの順番）に並び替えてデータを保存しています。
インデックスはこれを用いることで検索を早くしているのです。

ここで
>カラムの全てにインデックス貼ったほうがいいんじゃないの?

って言う疑問に対して
>「それはダメだよ！」

って言うための説明ができます。
つまりインデックスをはると言うことは通常テーブルとは別にインデックス用ののテーブルとの２箇所にテーブルに対してデータが保存することになります。なのでインデックスは検索の時は早くなるのですが、データを２箇所に保存する分処理が多くなってしまうという欠点があります。
なので、全てにインデックスはるのはよくないことです。（もちろんケースバイケースであると言うことは前提の上でですが）

**一般的にインデックスを貼ったほうがいい条件について**

- 検索対象の行数が多い
- 検索対象表において検索項目の重複や重なりが少ない（例：外部キーなど）
- 検索対象の更新が少ない
- 検索対象の追加・削除が少ない

この４項目がインデックスをはる条件になってます（なんども言いますが、ケースバイケースではあります😓）

# トランザクション
## ざっくりトランザクションって？
<img width="700" alt="スクリーンショット 2020-03-21 21.49.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281558/c3567536-342e-f177-6418-ee96d608d7a5.png">

親のA子さんは子供のB君に1000円おこずかいをあげようとしました

<img width="700" alt="スクリーンショット 2020-03-21 22.05.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281558/1cdb1145-2e35-59b9-ddc0-5342c0e9c9da.png">
その時データベース上では、、、

- A子さんの財布から1000円減らす処理
- Bくんの財布に1000円増やす処理

この2つが行われます。
<img width="700" alt="スクリーンショット 2020-03-21 22.09.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281558/6ebb6af7-2516-fb61-4927-66a3c7c2fcb9.png">

しかしなにかしらの理由でAさんの財布から1000円減らす処理はすることはできましたが、B君の財布に１０００円増やすことができなくなりました。
この時１０００円はデータベース的には消えて無くなってしまっている状態です。（これはとてもまずい、、、）

１０００円はどこにいったんだ〜！！！！

ここで登場するのがトランザクションです。
トランザクションっていうのは今回の場合

- A子さんの財布から1000円減らす処理
- Bくんの財布に1000円増やす処理

という2つの関連する処理が正確に実行が完了されなかった場合
そもそも取引自体が無かったことにするというものです
<img width="700" alt="スクリーンショット 2020-03-22 0.10.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281558/a136a0e6-6f6f-baad-b361-60fa3e64cf5c.png">

つまり、A子さんの財布からは１０００円は減りませんし、B君の財布にも１０００円増えることはありません。

これがトランザクションです。

## ちゃんトランザクションを考える

ざっくりとトランザクションがわかったところで具体的にはどうやってトランザクションが行われているのでしょうか？
トランザクションには、、、

- 一連の処理が正常に完了し処理を確定させる`COMMIT`
- 何かしらの異常があったときに処理をなかったことにする`ROLLBACK`

の2つが存在します。

さっきの例で行くと、、、
<img width="692" alt="スクリーンショット 2020-03-24 10.36.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281558/a5385b46-4ba7-f7a8-725a-54c5b2b1eaa2.png">

こんな感じでトランザクションがスタート→コミットされていきます

もし、トランザクション中にエラーが起こった場合は、、、
<img width="1204" alt="スクリーンショット 2020-03-24 10.36.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281558/7ab61152-82b9-4092-07a9-21b3906b7826.png">

ROLLBACKが走り、処理をのものがなかったことになります。

これらの機能は
## ACID特性
と呼ばれ標準規格となっています

### 1. 原子性(Atomicity)
トランザクションが終わった時に、そこに含まれていた更新処理は全て実行されるか、全て実行されない状態で終わることを保証する性質。
COMMITで更新が確定されるか、ROLLBACKで元に戻されるかの二択というイメージです。

### 2. 一貫性(Consistency)
トランザクションに含まれる処理はそれぞれの制約を満たすという性質。
トランザクションの途中で制約違反の処理があった場合、処理を中断してトランザクション実行前に戻すことでデータの一貫性が保たれる。そのため、あるデータは更新されているが、その他のデータは更新されないというような状態を持たないということ。

### 3. 独立性(Isolation)
あるトランザクションが実行中の場合、もう一方のその他のトランザクションの影響を受けないという性質。
トランザクション実行中に、その他のトランザクションがデータの更新を行ったとしても実行中のトランザクションはその更新結果の影響を受けないというイメージ。

### 4. 永続性(Durability)
トランザクションが完了した後、そのデータ状態が保存され失われることは無いという性質。
この性質の保証のために、一般的にはトランザクションのログを記録しておき、障害が起きた場合はログを使用して障害発生前の状態に復旧する。

# デッドロック

### ざっくりデッドロックって？
<img width="700" alt="スクリーンショット 2020-03-22 0.52.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281558/e124763f-02c8-c678-cc59-e725c0a23c48.png">
いつもおこずかいをもらってたB君はたまには自分もA子さんにお返しをしようと考えていました。


<img width="700" alt="スクリーンショット 2020-03-22 13.22.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281558/8a3f74ad-60e1-31bf-2a27-c9c81782d1cd.png">


しかし、タイミング悪くA子さんとBくんは全く同じタイミングでお互いにお金を渡そうとしてしまいました。
現実の世界なら普通に1000円を交換すればいいのですが、、、

これがデータベース上で起こってしまうと大変です、、、なぜ大変なのかというと、、、
![スクリーンショット 2020-03-22 15.45.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281558/cd47998e-e735-cc69-6e4c-4e625147e644.png)
上の図のようにAさんの処理もBさんの処理も両方ともお互いの処理の終了を待っているせいで処理が進まなくなってしまっている状態のことを指します。


#まとめ
ざっくりと、インデックス・トランザクション・デッドロックをまとめてみましたが、それぞれDBを触る時の基礎知識となっているのでまずはざっくりベースで覚えておくといいと思います