DB関連まとめ(index, transaction, foreign key, 正規化など)

DBに関して学習したことをまとめました。

# DB関連
## indexの仕組み。なんで早くなるのか？
**B-treeにより、データをフルスキャンしなくて済むようになるため**

[補足]
indexを貼らないと、大量のレコードが入っているテーブルから1行のレコードを検索するのに頭から順番に検索する→時間がかかる
indexを貼る事によって二分探索木→AVL木の良い点を引っ張ってきて改良された
B-treeという`AVL木が一般化され、かつ多分岐の平行木構造を持ったもの`が使われ、並び替えを行う事が無くなるため処理が高速になります。

普通は 1 ~ 10まである中で8を検索したい際に
1-2-3-4-5-6-7-8と発見されるが

二分探索を使うと

[![https://gyazo.com/2d0e4613213fe8f17295e44f15ec8a79](https://i.gyazo.com/2d0e4613213fe8f17295e44f15ec8a79.png)](https://gyazo.com/2d0e4613213fe8f17295e44f15ec8a79)

のように（10までしかないので少ないが), 8は6より大きい→9へ 9より小さい→8へ　という感じで2回で見つけることができる

たった10個でここまで見つける回数が減るので、データの量が増えれば増えるほど効果が出てくる

## indexを貼る場所について

とりあえず
すべてのカラムにindexを貼って、EXPLAINすると, possible_keysに利用したほうがいいkeysが示される
それが複数であった場合に複合キーを作ってクエリを投げるとうまくindexが貼れている状況になる。

[詳細]

- 複合INDEXを貼るときは　極力UNIQUEになるよう
- WHERE句とORDER BY句が存在するSQLには付けたほうがいい
- より絞り込める順番でINDEX貼ること(問題がなければ無視してINDEXを貼らない)

要はデータが少量の時は貼ってもあまり意味がなく、逆に多いテーブルにむやみに張りすぎるとサーバー容量を圧迫する可能性があるので、`どう絞り込めるか`を意識してはる

実験URL →　http://polidog.jp/2013/11/24/mysql/

## foreign key とは

**外部キーとは、テーブルのある列に、別のテーブルの特定の列に含まれる項目しか入力できないようにする制約**

Posts table

|id|content|
|:---|:---:|---:|
|1|great|

Likes table

|id|post_id|
|:---|---:|
|1|1|
|2|1|
|3|2|

上記の例ではlikes tableのid 3でpostのid 2がないので外部キーによって保存されない


## transaction 実際に使う場面
**トランザクションとは複数のレコードの保存・更新を一つの単位にまとめて行う事
あるものは保存されて、あるものは保存されないという状態を防げる**

## 正規化

### 正規化の目的

**データベースで保持するデータの冗長性や非一貫性の問題を解決するために考案された方法論**
エンティティの分離とリレーションシップや外部キーの設定を繰り返すことでデータの整理をする

#### (正規化の前に)関数従属性とは
y = f(x)のことでxが決まればyが決まるということ。yはxに従属している

## 第1正規化、第2正規化、第3正規化の要約

#### 第1正規化

- 一つのセルの中に一つの値しか含まない状態にすること
- テーブル内に繰り返されるレコードをなくすこと。

#### 第2正規化

- テーブル内の部分関数従属を解消し、完全関数従属のみのテーブルを作ること
- 複数のレコードで重複している内容を別のテーブルとして管理すること

部分関数従属-> (主キーの一部の列に対して従属する列がある場合)
完全関数従属-> (主キーを構成するすべての列に従属性がある場合)

#### 第3正規化

- 推移的関数従属を分離すること


## 正規化はなぜ必要なのか
非正規形のテーブルを例に用いて説明する
以下のような学生とその学生が受ける大学の授業を管理するためのテーブルがあったとする



|id|school_code|school_name|student|homeroom|class1|class2|class3|  
|:-:|:-----:|:---:|:-----:|:------:|:----:|:----:|:-----:|
|1|001|あ大学|田中太郎|3-9|経済学|倫理学|経営学|
|2|001|あ大学|四谷四郎|1-2|経済学|考古学|心理学|
|3|002|は大学|大塚花子|2-5|経済学|倫理学|物理学|



```
このテーブルの問題点が二つあります
- 一つのせるの中に二つの値を含んでいる
- 重複情報が存在する
- エンティティの属性の中に他のエンティティの情報が含まれる
```


#### 第一正規形
- 一つのセルの中に一つの値しか含まない状態にすること
- テーブル内に繰り返されるレコードをなくすこと。
classというレコードが繰り返されていたので、第一正規化に従って繰り返されるレコードをなくす

|id|school_code|school_name|student|homeroom|class 
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|001|あ大学|田中太郎|3-9|経営学|
|2|001|あ大学|田中太郎|3-9|経済学|
|3|001|あ大学|田中太郎|3-9|倫理学|
|4|001|あ大学|四谷四郎|1-2|経済学|
|5|001|あ大学|四谷四郎|1-2|考古学|
|6|001|あ大学|四谷四郎|1-2|心理学|
|7|002|は大学|大塚花子|2-5|経済学|
|8|002|は大学|大塚花子|2-5|物理学|
|9|002|は大学|大塚花子|2-5|倫理学|

#### 第二正規化
- テーブル内の部分関数従属を解消し、完全関数従属のみのテーブルを作ること
- 複数のレコードで重複している内容を別のテーブルとして管理すること
大学名が大学コードのみに従属しているので分離

studentsテーブル

|id|school_code|student|homeroom|
|:-:|:-:|:-:|:-:|:-:|
|1|001|田中太郎|3-9|
|2|001|四谷四郎|1-2|
|3|002|大塚花子|2-5|

schoolsテーブル

|id|school_code|school_name|
|:-:|:-:|:-:|:-:|
|1|001|あ大学|
|2|002|は大学|

subjectsテーブル

|id|name|student_id|
|:-:|:-:|:-:|:-:|
|1|経営学|1|
|2|経済学|1|
|3|倫理学|1|
|4|経済学|2|
|5|考古学|2|
|6|心理学|2|
|7|経済学|3|
|8|物理学|3|
|9|倫理学|3|

#### 第三正規化
- 推移的関数従属を分離すること
{大学コード,大学名} -> {homeroom} -> {something}
という二段階の関数従属が存在します。このような段階的な従属関係のこと
- 中間テーブルを作成して、idを互いにを紐付ける

studentsテーブル

|id|school_code|student|homeroom_id|
|:-:|:-:|:-:|:-:|
|1|001|田中太郎|3|
|2|001|四谷四郎|1|
|2|002|大塚花子|2|

schoolsテーブル

|id|school_code|school_name|
|:-:|:-:|:-:|:-:|
|1|001|あ大学|
|2|002|は大学|

homeroomsテーブル

|id|name|
|:-:|:-:|
|1|1-2|
|2|2-5|
|3|3-9|

subjectsテーブル

|id|name|
|:-:|:-:|
|1|経営学|
|2|経済学|
|3|倫理学|
|4|物理学|
|5|考古学|
|6|心理学|

students_subjectsテーブル(中間テーブル)

|id|student_id|subjects_id|
|:-:|:-:|:-:|
|1|1|1|
|2|1|2|
|3|1|3|
|4|2|2|
|5|2|5|
|6|2|6|
|7|3|1|
|8|3|2|
|9|3|4|


## MVC

### controllerの役割

クライアントからリクエストを受信して、クライアントへレスポンスを送信する
その間にビジネスロジック(Model)を呼び出したり、出力(View)に引き渡したりする

### model (find, find_by, where)
```
find    一つの条件で一つのレコードを引っ張ってくることができる
find_by 複数の条件で一つのレコードを引っ張ってくることができる
where   複数の条件で複数のレコードを引っ張ってくることができる
```

```
users = User.all.limit(3)
=> [#<User id: 1, email: "aaa@gmail.com", admin: true>, #<User id: 2, email: "bbb@gmail.com, admin: true>, #<User id: 3, email: "ccc@gmail.com, admin: true>]

users.find(1)
=> #<User id: 1, email: "aaa@gmail.com", admin: true>


users.find_by(admin: true) #admin: trueが三つあるが取得するのは最初の一つ
=> #<User id: 1, email: "aaa@gmail.com", admin: true> 
  
users.where(admin: true)
=> [#<User id: 1, email: "aaa@gmail.com", admin: true>, #<User id: 2, email: "bbb@gmail.com, admin: true>, #<User id: 3, email: "ccc@gmail.com, admin: true>]
```

## url

### RESTfulとは(REST = Representational State Transfer)
ソフトウェアアーキテクチャのスタイルのひとつ、要は概念

- ステートレスなクライアント／サーバープロトコル
(サーバーはクライアントの状態を保持せずに、クライアントは毎度毎度送信する情報にすべてのやりとりを含めるということ)
- すべての情報に適用できる「よく定義された操作のセット」
簡単に言うとroutes.rbで記載するresources これはGET, POST, PUT, DELETEとかでやりたいことのすべてできますってこと。

- リソースを一意に期別する「汎用的な構造」
URL(locator), URI(Identifier)でhttp:などURLで決められておらず、技術仕様なためURI
一般的なhttps://の後の/../..//..みたいのがURLと呼ぶべき
URIの中にURLが含まれている

- ハイパーメディアの使用
アプリケーションの情報と状態遷移の両方を扱えるため、要はHTMLやXMLのことで
それを使うとテキストのみではなく、画像、動画、音楽、別ページリンクまで載せられるよってこと。


## debugの仕方
### rails cの使い方, binding.pry(+αも)

- rails c でdatabaseのデータを持った上でデバッグすることができる
- binding.pryではその行の前後で処理を止めdebugモードにさせることができる
- gem better_errorsではブラウザ上で変数の中身などを確認することができる
- failをコード上に書くと、その場でfailしてくれてデバッグすることができる