データベース 学習

データベーススペシャリスト試験勉強用。



# DBとは

Database（データベース）とは、データの集合のことを指す。

「データ」とは**特定の形式にフォーマットされた事実**のことを指し、「情報」とはデータを特定の文脈や観点に従って集約または加工、抽出されたものを指す。

# DBMSとは

DBMS（Database Managemant System）はデータベースを実装したソフトウェアを指す。

混同しやすいのは、DB自体は単体では使うものではなく、DBMSを介して利用するということ。会話の中では「DBMS」を指して「DB」と言ったりするため、厳密には違うということを理解しておきたい。


# DBのモデル
DBの代表的なモデルはリレーショナルDBだが、リレーショナルDBはいくつかの種類のうちの一つにすぎない。

- **RDB**
    - Relational Database
    - リレーショナルデータベース
    - 表形式（テーブル）データを管理する
    - **SQL**（Structured Query Language）を用いてデータを操作する
    - Oracle Database、SQL Server、PostgreSQL、MySQL
- NoSQL
    - Not Only SQL
    - スキーマが存在せず、RDBよりも柔軟性が高い
    - MongoDB、Redis、Apache Cassandra、Neo4j
    - キーバリュー型ストア
        - KVS、Key - Value Store
        - Key と Value による単純構造
        - 高速
    - XMLDB
        - XML Database
        - XML形式の階層構造でデータを扱う
- 列指向データベース
    - 行指向データベース（RDB）と対比される文脈で使用される分類
    - Apache Cassandra、HBase
- オブジェクト指向データベース
    - OODB、Object Oriented Database
    - データと操作をオブジェクトにまとめて管理する
    - Java、C++などの言語が採用している
- グラフデータベース
    - データをノードとエッジのネットワーク関係で保存、管理する
    - Neo4j、ArangoDB
- メモリデータベース
    - メインメモリ（主記憶装置。物理的にはRAM）上にデータを保持する
    - 一時的なデータやキャッシュに利用される
    - Redis、Memcached
- 時系列データベース
    - センサーデータやログデータなどを保存、分析するために特化したもの
    - InfluxDB、TimescaleDB

    
## RBDの製品
- Oracle Database
    - Oracle社製
    - Windows OS、Linuxのマルチプラットフォーム対応
    - 有料（商用利用時）
- SQL Server
    - Microsoft社製
    - Windows OSでのみ使用可能
    - 有料（商用利用時）
- DB2
    - IBM社製
    - Windows OS、UNIX系OSのマルチプラットフォーム対応
- PostgreSQL
    - 米バークレイ大学製
    - 無料（OSS）
- MySQL
    - サン・マイクロシステムズ　→　Oracle社製
    - 無料（OSS）




# 3層スキーマ

構造を論理的に分類するためのモデル。

- **外部スキーマ**
    - External Schema
    - 外部モデル
    - エンドユーザやアプリケーションがデータにアクセスするためのインターフェース
    - [ビュー](#ビュー)
    - データの物理的な格納方法や内部構造について意識しない
    - [概念設計](#概念設計)の対象
- **概念スキーマ**
    - Conceptual Schema
    - 論理データモデル
    - [エンティティ](#エンティティ)、[テーブル](#テーブル)、またはそれらの**関係性**の定義
    - 開発者の立場から見たDB
    - [概念設計](#概念設計)、[論理設計](#論理設計)の対象
- **内部スキーマ**
    - Internal Schema
    - 物理データモデル
    - データベースの物理的な実装（どのような方法、ファイル形式で管理や保管するか）
    - [インデックス](#インデックス)
    - [物理設計](#物理設計)の対象


昔は概念スキーマが存在せず外部スキーマと内部スキーマのみであったが、両者の依存性が高いために、アプリケーションの仕様変更やデータの物理的な格納方法変更が広範囲に影響を与えた。

そこで両者の依存を弱めることを目的として概念スキーマが登場した。

概念スキーマによって外部スキーマはデータベースの内部構造を意識する必要がなくなる（その逆も然り）。

:::note info
概念スキーマは内部スキーマを**仲介**することで両者の依存を弱め、変更に対する柔軟性を提供する。
:::


# 設計

設計にはそれぞれ**概念設計**、**論理設計**、**物理設計**と呼ばれる工程がある。これらの分類は正確に3層スキーマと対応するものではないが、概ね以下のような位置付けとなっている、

外部スキーマ ↔ 概念設計
概念スキーマ ↔ 概念設計、論理設計
内部スキーマ ↔ 物理設計

概念設計と論理設計は厳密に区別できない場合がある。概念設計は「データの意味とその関係を理解し、視覚化することによって要件を正確に捉えること」に焦点を当てて行うのに対して、論理設計では、「概念設計で作成したデータモデルを具体的かつ効率的なデータベース構造に変換すること」に焦点を当てて行う。

:::note info
概念設計　▶️　データの意味とその関係を理解し、視覚化することによって要件を正確に捉えること
論理設計　▶️　概念設計で作成したデータモデルを具体的かつ効率的なデータベース構造に変換すること
:::


また、概念設計の成果物は主にER図なのに対して、論理設計の成果物は正規化されたテーブル定義やデータモデルとなる。ただし、論理設計ではER図のブラッシュアップが行われることもあり、両者を明確に区別できない場合がある、

論理設計では原則、特定のDBMS（内部スキーマ）に依存しない形でデータ構造を定義する。

一般的には以下の順に行われる。

![データベース.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/3a2f2f20-b045-be39-4167-58c03ab6cb7d.png)

## 要件分析

システムが必要としているデータの種類、データ同士の関係、制約、必要な操作を分析し、「何を」「どのようなフォーマットで」保存するかを決定する。

データフローを理解することも必要とされる。

初めてシステム化されるなどの場合、データがデータベース向けに整理されていない事があり、**データクレンジング**と呼ばれるデータフォーマットが必要になることもある。


## 概念設計

[ER図](#-ER図)や**UML**（Unified Modeling Language）を使用して現実の世界をモデル化する設計工程。概念設計により作成されるデータモデルを **概念モデル** と言う。

概念モデルとは、エンティティやエンティティ同士の関係、属性、制約などの定義を指す。

またこの段階で作成する[ER図](#-ER図)はまだ[正規化](#-正規化)を行なっておらず、おおまかなエンティティとその関係性だけを表現したものになる。

### トップダウンアプローチ

システム全体の概念を最初に定義し、それを段階的に詳細化していく手法。大きな枠組みから出発し、徐々に具体的な部分に焦点を当てていく。

```:トップダウンアプローチ
要件分析
　⬇️
ER図作成
　⬇️
属性の洗い出し。キー、制約の設定
　⬇️
正規化
```

システム全体を俯瞰できると言う利点があり、大規模システムに向いている。また本来どうあるべきかと言う視点で進められるため、理想的なデータモデルを構築することができる。

一方で、設計の初期段階で要件定義をする必要があるためエンティティに過不足が発生しやすく設計の難易度が高い。そのため、高いスキルが求められ、設計の変更が発生しやすいことなどがある。

### ボトムアップアプローチ

既存のデータや小さなデータ単位から出発し、それらを組み合わせて全体のシステムを構築する手法。具体的なデータやプロセスからスタートして、徐々に大きな構造を作り上げていく。

```:ボトムアップアプローチ
属性の洗い出し。キー、制約の設定
　⬇️
正規化
　⬇️
ER図作成
```

具体的なデータに基づいた設計を行うため、現実に即した設計ができ、小規模なシステムに向いている。一方で、全体の構造が最後まで見えないため、全体の一貫性を保ちづらい、細部がうまく噛み合わず設計が非効率になりやすいと言う欠点がある。

## 論理設計
Logical Design

概念モデルをもとにしてテーブルの構造、カラムやキーなどの制約条件の定義を行い **論理データモデル** を作成する。

## 物理設計
Physical Design

論理設計で作成されたテーブル定義書を基に、データベースのパフォーマンスや効率を考慮して、実際のDBMS上にデータベースを構築する。インデックスの作成やストレージの最適化などを行う。

物理設計で作成されるデータモデルを **物理データモデル** と言う。

```
インデックス設計
　　　⬇️
物理的なストレージの選定
　　　⬇️
ストレージの冗長構成の決定
　　　⬇️
ファイルの物理配置
　　　⬇️
パフォーマンスチューニング
```


# ER図
Entity-Relationship Diagram

実体関連図。

その名の通り、[エンティティ](#エンティティ)とリレーション（関係）を可視化した図のこと、

ER図を作成する際に注目すべきポイントは**主キー**。主キーを中心に見ていくことで**1対1**、**1対多**、**多対多**などのテーブル同士の関係性に気が付きやすくなる。

1対1、1対多、多対多などのテーブル同士の関係性を[カーディナリティ](#カーディナリティ)と言う。

## エンティティ

日本語で「実体」。

物理的に存在する「顧客」「商品」「人物」を指すこともあれば、物理的実体を伴わない「注文履歴」「注文」などを指すこともある。

エンティティはテーブルにおいて**属性**（列）という形で管理される。

エンティティは長方形で表現する。

![entity.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/bd698d4a-9c78-89dc-398f-44dc5c88dcd2.png)

エンティティには複数の属性が含まれることがある。なお、属性はER図において省略される場合がある。

![entity_attribute.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/1ea6013b-24ba-5f78-72e4-9b3dcc7beea5.png)

主キー属性は上に記載し、非キー属性は下に記載する。

![entity_attribute_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/17ebbecf-a7e8-9564-620b-d09997474be8.png)

概念データモデルと関係スキーマは対で作成される。

![schema.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/edacd547-301d-4776-bc4b-62f213f7da13.png)

### 強エンティティ / 弱エンティティ

単独で存在できるエンティティを**強エンティティ**と言い、強エンティティが存在して初めて存在することができるエンティティを**弱エンティティ**と言う。

「注文」は単独で存在することができるため強エンティティに分類されるが、「注文明細」は「注文」の存在があって初めて存在することができるエンティティであるため、弱エンティティに分類される。

## カーディナリティ
Cardinality = 濃度

様々な文脈で使用される用語。

エンティティ間にリレーションが存在する時、一方のエンティティに対応するもう一方のエンティティのレコード数を**カーディナリティ**と言う。

以下の4つがある。

| カーディナリティ |  |
|:-:|:-|
| [1対1](#1対1) | 例：社員とパスポート<br>1人の社員に対してパスポートは複数存在しない<br>反対に、1つのパスポートに対して複数の社員は存在しない |
| [1対多](#1対多) |  例：親と子<BR>1人の親は複数の子を持つことができる<BR>反対に、それぞれの子は1人の親としか関連しない |
| [多対1](#多対1) | 例：兄弟姉妹と親<br>複数の子が1人の親に関連する<br>反対に、1人の親は複数の子（兄弟姉妹）に関連する |
| [多対多](#多対多) | 学生と受講コース<br>各学生は複数のコースを受講できる（1人の学生に着目すると、その学生は複数の受講コースを持ち、同じような学生が複数存在する）<br>各コースは複数の学生から受講される（1つのコースに着目すると、そのコースは複数の学生から受講されていて、同じようなコースが複数ある） |

## 1対1

![entity_one_to_one.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/265ae6ba-2db1-d014-628f-8229ade2987e.png)

## 1対多

![entity_one_to_many.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/fd13db4b-51df-11a6-2b0b-600cba91c78a.png)

エンティティが常に1以上存在する（⚫︎）とき、次のように表現する。

![entity_0_over.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/82980033-c9dd-381d-ac8a-d3eea25544c3.png)

一方のエンティティが存在しない（◯）場合があるときは、次のように表現する。

![entity_1_over.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/0df3a8e1-520e-f5fe-2a01-86cc37c8d034.png)

## 多対多

![entity_many_to_many.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/b42cae4b-c1ae-a21e-5a89-cb9ba9916982.png)

多対多の関係は、一方を特定するためのキーを持たないため、好ましくないとされる。多対多の関係を解消するには、2つのテーブルの間に[連関エンティティ](#連関エンティティ)と呼ばれるエンティティを作成する方法がある。

## 連関エンティティ
associateive entity

多対多の関係はデータモデルとしての表現はできるが、実装することができない。「多対多」の関係を2つの「1対多」の関係に分解して、連関エンティティに双方のエンティティ間の関係情報を管理させる。

連関エンティティは連結エンティティ、関連エンティティと呼ばれることがある。

![entity_associative.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/baa6cbc0-157e-f5ca-7b42-265e745ea06a.png)

:::note info
連関エンティティは、「多対多」の関係に介入することで「多対多」の関係を「1対多」の関係に分解する
:::

## スーパータイプ / サブタイプ

複数の子エンティティが共通の親エンティティを持つとき、親エンティティを**スーパータイプ**、子エンティティを**サブタイプ**と表現する。

オブジェクト指向プログラミングと同じで、親から子への方向を**特化**、子から親への方向を**汎化**と言う。

サブタイプには排他的サブタイプと共存的サブタイプがある。

### 排他的サブタイプ
Mutually Exclusive Subtypes

スーパータイプが、一つのサブタイプにしか属さない。

具体例として、スーパータイプ「従業員」に対するサブタイプ「正社員」「パートタイプ社員」などがある。

![entity_super.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/034dfc70-ec38-c5db-3de8-69a6b1655966.png)

### 共存的サブタイプ
Overlapping Subtypes

スーパータイプが、複数のサブタイプに同時に属することができる。

具体例としてスーパータイプ「アプリケーション」に対する「ゲームアプリ」「教育アプリ」などがある。

![super_type_overlapping.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/fc7ba353-6d73-0563-15f6-9061d1d210ca.png)


# 制約

## 検査制約
`CHECK`

属性の取りうる値の範囲を制限する（特定の範囲内の値しか登録できない）ための制約。

```sql:CHECK
CHECK (condition)
```

`condition`の例としては範囲を制限するものがある。

```sql:CHECK　例
CHECK (column_name > 0)
```

```sql:CHECK　例
CHECK (column_name IN (0, 1, 2, 3))
```

## 一意性制約
`UNIQUE`

（主キー以外の）特定の属性（列）において他のレコードとの重複を許容しないための制約。[候補キー](#候補キー)に対して使用される。

## NOT NULL 制約
`NOT NULL`

属性値にNULLを許容しないための制約。可能な限り設定した方が良い。

## 主キー制約
`PRIMARY KEY`

テーブル内で値が一意であることを保証するための制約。[一意性制約](#一意性制約)と[NOT NULL 制約](#not-null-制約)を組み合わせたもの。

## 参照整合性制約
`REFERENCES`

子テーブルの[外部キー](#外部キー)が別の親テーブルの[主キー](#主キー)または一意のキーを参照することを保証するための制約。外部キー制約とも呼ばれる。

親のテーブルの主キー、一意のキーに存在しない値を子のテーブルの外部キーに許可しないようする事ができる。

例えば「部署」、「社員」というテーブルがあった時に、部署テーブルの主キーに存在しない部署IDを、社員テーブルの所属部署IDとして格納することはできない。

## カスケード
`CASCADE`

[参照整合性制約](#参照整合性制約)が存在するテーブルにおいて、親テーブルでの変更や削除が子テーブルにも影響を与えること。

親テーブルの変更や削除が起きた場合、整合性を保つためには更新された親テーブルのデータを参照する子テーブルのレコードに対して、何らかのアクション（**カスケード操作**）が必要となる。

例えば、親テーブルで主キーの属性値が1つ削除された場合に、もし子テーブルでその属性値を参照していたら、存在しないデータを参照していることになってしまうため削除しなければならない。

もしこのようなカスケード操作が必要になってしまったら、データ削除は親からではなく子から削除するようにして、カスケード操作自体がなるべく発生しないようにした方が良い。

:::note info
カスケード操作は、なるべく必要にならない方が良い
:::

# ページ

データをディスクに格納するための最小単位を **ページ** と言う。データベースは大量のデータを扱うため、ディスクに保存する際はこのページ単位でデータを扱う。

データベース製品の使用によって異なるものの、一般的にページは2000バイト(2KB)、4000バイト(4KB)、8000バイト(8KB)、16000バイト(16KB)などの固定サイズになっている。

ページは、データベースエンジンがデータを読み書きする際の基本単位になるため、例えデータの更新が1レコードの1カラムに関わるほんのわずかなものであったとしても、更新するレコードを含むページがディスクからは読み込まれる。

ページにはいくつかの種類がある。

## データページ

テーブルのレコードが格納されるページ。

## インデックスページ

インデックス情報が格納されるページ。

## LOBページ

テキストやバイナリデータなどの Large Object を格納するためのページ。

テキスト型の LOB は **CLOB** (Charactor LOB)、バイナリ型の LOB は **BLOB** (Binary LOB) と呼ばれる。

## トランザクションログページ

トランザクションログが格納されるページ。障害時のリカバリに利用される。

# インデックス

データベースにおいて検索速度を向上させるために使用されるデータ構造を**インデックス**という。

インデックスは、テーブルの特定の列（または列の組み合わせ）に対して作成され、クエリの実行速度を大幅に改善させる。

ソート操作にも有効で、特定の列にインデックスがある場合、その列に基づくソートが高速に行うことができる。

:::note info
インデックスは、テーブルの特定の列（または列の組み合わせ）に対して作成され、クエリの実行速度を大幅に改善させる
:::


ただしデータベースにとってインデックスの設定は必須のものではなく、あくまでもパフォーマンス向上のためのものである。

またインデックスの実体は、特定の列の値（キー）と、その値が格納されているレコード（実データ）への**ポインタ**（参照）がプログラミング言語のMapのような形で保持されたもの。[Bツリーインデックス](#Bツリーインデックス)やハッシュインデックスなどの形で実装される。

:::note info
インデックスの実体は、
key：列
value：レコードへのポインタ
の key-value マップ
:::

実装方式には様々あるものの、実際には他のデータ構造と比べて多くの側面で平均点以上の性能を持つオールラウンド型であるBツリーインデックスが選択されることがほとんど。

## クラスタリングインデックス

key-value形式で保存される複数のデータを、記憶装置の同じ場所に物理的に固めて格納することを**クラスタリング**という。クラスタリングされていないインデックスはすべて、非クラスタリングインデックスになる。

まとめて格納されることで、`BETWEEN`や比較演算子によって範囲を指定した検索時に、検索対象データが物理的にまとまった位置から取得することができる。

クラスタリングインデックスは1つのテーブルに対して、1つしか設定できないため、主キーに対して設定することが最も効果的とされる。

:::note info
クラスタリングインデックスは、1つのテーブルに1つしか設定できないため、主キーに設定することが効果的
:::


## Bツリーインデックス

最も一般的なインデックス。（Bツリーの「B」には特に意味がない）

Bツリーインデックスは、**ツリー構造**によってデータを管理し、そのうちリーフ（末尾のノード）だけが実データへのポインタを保持している。

**平衡木**（Balanced Tree）と呼ばれる構造になっていて、ルートからリーフまでの深さが全方向で等しいため、キーの値に関わらず常に同じ計算量でルートからリーフまでたどり着く事ができるとされる。平衡木はバランス木とも呼ばれる。

:::note info
平衡木はすべてのリーフの深さが均一なツリー構造
:::

ただし、テーブルの更新を繰り返すことによって平衡木構造が少しづつ崩れていくため、探索コストは徐々に均等でなくなっていく。そのため、インデックスを作成した属性（列）自体の値が更新されるような場合、定期的にインデックスを作成し直すメンテナンスを行う必要がある。

Bツリーにおける検索の計算量は、ツリーの深さ（の最大値）に依存し、データ数には単純比例しない。そのため通常、レコード数が1万を超えるような**大規模なテーブルに対して使用する事が効果的**。小規模なレコード数の場合、インデックスを作成しない方が、よりパフォーマンスの良いことがある。

## 設計におけるインデックス

インデックスはデータ検索時のパフォーマンスを大幅に改善させ得るものである一方で、設定することでかえってパフォーマンスが悪くなる場合もあるため、その点を考慮した設計が必要になる。

具体的にはインデックスの設定は`SELECT`文に対してはパフォーマンス向上の要因となるが、`INSERT`、`UPDATE`、`DELETE`文に対しては実行の度にインデックスの再構築が必要になるため、パフォーマンス低下の要因になる。

そのため、**データの更新頻度**がインデックス設定の可否を決める上で重要となる。また、検索時にあまり利用されない列に対してインデックスを設定することは避けるようにする。

:::note info
インデックスはデータの更新頻度を加味して設計する
:::

データの量がそれほど多くない場合、インデックスを使用した検索よりも、単純な検索の方が高速な場合もある。

その他、以下の点に留意する。

- 不等号（`<`、`>`、`<=`、`>=`）、`BETWEEN`に対してもインデックスは有効だが、否定条件（`<>`、`!=`）に対しては効果がない
- カーディナリティ（属性が取りうる値のバリエーション）が高い属性に対して使用することによって、データ全体に対して検索対象を大幅に絞り込むことができる。ただしこの場合、データの分布が特定の属性値に偏っているデータに対しては効果が薄い
- SQL文の`WHERE`句、結合条件に指定される属性に対して使用する
- SQL文の中でインデックスを作成した属性を演算して利用してしまうと効果がなくなる
- `IS NULL`を使用しても効果がなくなる
- `OR`を使用しても効果がなくなる
- 暗黙の型変換が行われている場合も効果がなくなる
- 主キー、一意制約を設定した属性に対しては内部で自動的にインデックスが作成されるため、改めて作成する必要はない

:::note info
インデックスは、不等号（`<`、`>`、`<=`、`>=`）、`BETWEEN`に対して有効
否定条件（`<>`、`!=`）に対しては効果がない
:::

# トランザクション

トランザクションが満たすべきとされる特性は[ACID特性](#acid特性)と呼ばれる。

## ACID特性

### 原始性 / Automicity

トランザクション内の操作は、「成功する（コミット）」か、または「失敗する（ロールバック）」かのいずれかにしかならないことが保証された状態。部分的に操作が成功することがない。

### 一貫性 / Consistency

トランザクションの開始前と後でデータの一貫性が失われないことが保証された状態。

異なる2つのトランザクションが存在するとき、どのような順番で実行しても最終的なデータの状態が同じになることを指し、**直列化可能性**、直列可能性とも言う。

### 独立性 / Isolation

複数のトランザクションを同時に実行しても、互いに干渉しないことが保証された状態。独立性のレベルには以下の4つの段階（**分離レベル**）がある。

これらの分離レベルは一般的に、程度が上がるにつれてデータの整合性が高まるが、処理負荷が増すためパフォーマンスは低下する。

:::note info
分離レベルを上げるほどデータの整合性は増すが、パフォーマンスは低下する
:::


#### `READ UNCOMMITED`

- 最も程度が低い分離レベル
- 他のトランザクションがコミットしていない変更も読み取ることができる（[ダーティリード](#ダーティリード)が発生する）

#### `READ COMMITED`

- 他のトランザクションがコミットした変更のみを読み取ることができる（[ダーティリード](#ダーティリード)が**発生しない**）
- 読み取ったデータが、他のトランザクション開始時点のデータであることが保証されていないため、実行元トランザクション内で同じクエリを複数回実行した際に、異なる実行結果になる可能性がある（[アンリピータブルリード](#アンリピータブルリード)が発生する）

#### `REPEATABLE READ`

- トランザクションが開始された時点のデータを読み取ることができる（[ダーティリード](#ダーティリード)が**発生しない**）
- 読み取ったデータが他のトランザクション開始時点のデータであることが保証されているため、実行元トランザクション内で同じクエリを何度実行しても常に同じ結果が得られる（[アンリピータブルリード](#アンリピータブルリード)が**発生しない**）
- トランザクションが完了するまでの間の他のトランザクションによる行の挿入、削除がブロックされない（[ファントムリード](#ファントムリード)が発生する）

#### `SERIALIZABLE`

- 最も程度が高い分離レベル
- 他のトランザクションがコミットした変更のみを読み取ることができる（[ダーティリード](#ダーティリード)が**発生しない**）
- 読み取ったデータがトランザクション開始時点のデータであることが保証されているため、トランザクション内で同じクエリを何度実行しても常に同じ結果が得られる（[アンリピータブルリード](#アンリピータブルリード)が**発生しない**）
- トランザクションが完了するまで、他のトランザクションによる行の挿入、削除をブロックする（[ファントムリード](#ファントムリード)が**発生しない**）

#### ダーティリード
Dirty = 汚れた、不正な

他のトランザクションが処理途中（コミット前）の不正確なデータが読み取られること。

#### アンリピータブルリード
Unrepeatable = 繰り返せない、再現できない

同じデータを読みとった際に、異なる結果が返されること。

トランザクション中に複数の読み取り処理が存在する場合に、他のトランザクションによる「コミット前」と「コミット後」のデータを1つのトランザクション内で読み取った場合に発生する。

#### ファントムリード
Phantom = 幻、幽霊

あるトランザクションが特定の範囲のデータを取得して複数回処理を実行しようとするとき、途中で別のトランザクションによってその範囲内に新たなデータが追加されたり既存のデータが削除されたりすることで、同じクエリを実行しているのに、途中で出現または消失する「幻のような」データによって取得結果が影響を受けること。

トランザクションが並行して実行される際に発生する。

# 耐久性 / Durability

トランザクション完了（コミット）後は、データが永続的に保存されることが保証された状態。仮に障害が発生したとしても、データを復旧させることができる。

# 物理的なストレージの選定

データベースの予想されるサイズ（容量）、成長率（どのようにデータが増加していくか）を見積もり、ディスクの種類（SSD、HDDなど）、RAIDの構成、ストレージキャッシュの設定などを行う。

基本的にはHDDを使用する。

**キャパシティ**（容量）のサイジングと**パフォーマンス**のサイジングという2つの観点から行う。

データの整合性とパフォーマンスには**トレードオフ**の関係が存在するため、「こちらを立てればあちらが立たず」の状況の中で、最適なものを選定するのは非常に難易度が高いとされる。

性能を考慮する上で**TPS**（Transaction Per Second）が指標として用いられる。

## データ所要量の見積もり

データをディスクに格納する際に必要となる容量は、以下の順に計算を行う。

[総行数](#総行数)　▶️　[ページサイズ](#ページサイズ)　▶️　[1行あたりのサイズ](#1行あたりのサイズ)　▶️　[1ページあたりの平均行数](#1ページあたりの平均行数)　▶️　[必要ページ数](#必要ページ数)　▶️　[データ所要量](#データ所要量)

## 総行数

見込まれるデータの総行数。

## ページサイズ

データを格納するのに最適な[ページ](#ページ)サイズ。

## 1行あたりのデータ容量

テーブルのレコード1行分のデータ容量。

## 1ページあたりの平均行数

[ページ](#ページ)には、実際には容量100%分のデータが格納されることはなく実際には何も格納されていないデータの空き領域が存在する。ページ対する空き領域の割合を**空き領域率**と言う。

空き領域率が低い場合、データの更新時にページが足りなくなることで、1つのデータを複数のページに分割して保存する「ページ分割」が発生し、パフォーマンスが低下する。

反対に空き領域率が高い場合、必要以上のページサイズが与えられていることになるため、ディスク容量の無駄遣いにつながる。

**1ページあたりの平均行数** を求めるには、まず1ページに対して実際どのくらいのデータが格納されているかを知る必要がある。これは

 > [ページサイズ](#ページサイズ)　❎　(1 - 空き領域率)

で求めることができる。


これを[1行あたりのデータ容量](#1行あたりのデータ容量)で除して **1ページあたりの平均行数** を求める。

> [ページサイズ](#ページサイズ)　❎　(1 - 空き領域率)　/　[1行あたりのデータ容量](#1行あたりのデータ容量)

## 必要ページ数

> [総行数](#総行数)　/　[1ページあたりの平均行数](#1ページあたりの平均行数)

で求めることができる。

## データ所要量

> [ページサイズ](#ページサイズ)　❎　[必要ページ数](#必要ページ数)

で求めることができる。

## ストレージの冗長構成の決定

データベースに保存されるデータは、基本的に消失が許されない。

ここでは**RAID**（Redundant Array of Independent Disk）という技術を使用し、データを冗長化させたり、パフォーマンスを高める。

選定としては可能な限り**RAID10**が望ましい。コストが問題になるようであれば**RAID5**も選択肢となる。

### RAID0

ストライピング。stripe=縞

データを複数のHDDに分散して保管する。

Input / Output にかかるスループット時間が分散されるため、処理時間が短縮されるが冗長性は向上しない。

### RAID1

ミラーリング。

2つのHDDに全く同じデータを重複した状態で保管する。

Input / Output にかかるスループット時間は短縮されないが、データの冗長性が増す。

### RAID5

パリティ分散。

最低３つの以上のHDDによって構成され、データ以外に**パリティ**と呼ばれる符号訂正符号を分散して保存する。

パリティはデータが壊れた際に使用される。データが失われた場合でも、パリティによってデータを復元することができる。

### RAID10

RAID1+10とも呼ばれる。

RAID1 と RAID0 を組み合わせたもの。最低4つ以上のHDDが必要で、コストが高い。

## ファイルの物理配置

- データファイル
- インデックスファイル
    - データファイルとは別に保存される
- システムファイル
- 一時ファイル
- ログファイル


## パフォーマンスチューニング

データベースのパフォーマンスを向上させるためのチューニングを行います。クエリの最適化、インデックスの調整、キャッシュ設定、クラスタリングなどが含まれます。

# 正規化

normalization=正規化
normal form（NF）=正規形

データの冗長性を除去することにより、**更新時異状**を防ぐことを目的として行う。更新時異状は、「異常」ではなく「本来の姿とは声となった状態になる」ことを指す。正規化は、設計において最重要とされる工程になる。

正規化は通常、第3までで十分とされ、それ以上の正規化は特定の状況下でのみ必要となる。第4次以上の正規化は**高次正規化**と呼ばれる。

正規化は機械的に行えば良いものではなく、要件によっては戸籍のように最新情報だけではなく情報の履歴を残す必要があるものがあり、その場合、あえて正規化を行わないという選択も必要になる。

また正規化による分解をすることによって、結合処理が必要になりパフォーマンスの低下を招くこともある。

:::note info
正規化は機械的に行うのではなく、時には「しない」という選択も必要
:::


## 第 1 正規形

意味を持つ最小単位のデータを**スカラ値**と言い、一つのセルに一つのスカラ値を格納する原則を**スカラ値の原則**と言う（scalar=単一の）。

ただし、実際にはスカラ値の原則に従っていないデータの方が稀で、違和感を覚える人が多いはず。

分割されたデータは結合することができるため、意味が破壊されない限り、データはなるべく分解したほうが良いとされる。

## 第 2 正規形

一つのテーブル内の[部分関係従属性](#部分関係従属性)を排除して、[完全関係従属](#完全関係従属性)のみにすること。

主キーが複数の属性の組み合わせ（𝐴,𝐵）である場合に、特定の属性（𝐶）が主キーのうちの一つの属性（例えば𝐴）にのみ依存している場合、部分関係従属性が存在する。

この時、テーブルを分解して[完全関係従属性](#完全関係従属性)のみにする（𝐴 を主キーとするテーブルと 𝐵 を主キーとするテーブルにする）ことで、複数の属性を含む主キーが単独の属性になる。これにより複数のエンティティをまとめて管理する必要が無くなり、構造がよりシンプルになる。

特に複数の重複したレコードの更新処理が1レコードだけで済む。


第二正規形によるテーブルの分解は可逆的な分解であるため結合によって元に戻す事ができる。また分解によってデータが失われないため**無損失分解**と呼ばれる。

結合は [`INNER JOIN`](#内部結合--inner-join) または [`OUTER JOIN`](#外部結合--outer-join) などのSQL文によって行う。コストがかかる処理であるため、正規化とコストはトレードオフの関係にある。

:::note info
正規化は検索（のための結合）処理のコストとトレードオフの関係にある
:::

正規化を行わないという選択肢もあり、この辺りは人によって考えがまちまちらしい。参考書に載っていた「『非正規化』は最後の手段と考える」というのがわかりやすかった。

### 関係従属

属性 𝑋 が属性 𝑌 を関数的に決定する、すなわち、𝑋 の値が同じであれば 𝑌 の値も必ず同じになる関係性。

`𝑋 → 𝑌` で表現する。 𝑋 を**決定項**、 𝑌 を**従属項**（もしくは被決定項）と言う。

### 完全関係従属性

`𝑋 → 𝑌` が完全関係従属性である場合、𝑌 が 𝑋 の部分集合に依存しない関係性を指す。

例えば `(𝐴, 𝐵) → 𝐶` が完全関係従属性である場合、𝐶 は (𝐴, 𝐵) の組み合わせに依存しているため、 𝐴 または 𝐵 のどちらか片方だけには依存しない。

### 部分関係従属性

`𝑋 → 𝑌` が部分関係従属性である場合、𝑌 が 𝑋 の部分集合に依存している状態の関係性を指す。

例えば `(𝐴, 𝐵) → 𝐶` が部分関係従属性である場合、𝐶 は  𝐴 または 𝐵 のどちらか片方に依存していて、決定項が (𝐴, 𝐵) である必要がない。

### 自明な関係従属性

当たり前に（常に）存在する関係従属性。

𝐵 が 𝐴 の部分集合であるとき、`𝐴 → 𝐵` が常に成立すること。 

部分集合 𝐵 が既に 𝐴 に含まれているため、𝐴 が定まれば 𝐵 の値も自動的に定まる、という意味で自明。

## 第 3 正規形

一つのテーブル内の[推移的関係従属性](#推移的関係従属性)を排除すること。

第3正規形による分解後の元のテーブルには[外部キー](#外部キー)が残る。

第3正規形も第2正規形と同様に無損失分解であり、結合操作によって元の形に戻す事ができる。

### 推移的関係従属性

`𝑋 → 𝑌` かつ `𝑌 → 𝑍` の場合に、 `𝑋 → 𝑍` が成り立つ関係従属性のこと。ただしこの時、`𝑌 → 𝑋` は成り立たないことが前提。


## 第 3.5 正規形

**ボイス・コッド正規形**（Boyce-Codd Normal Form）とも呼ばれる。

高次正規形の一つであり、第 3 正規形を強化したものという位置付け。

高次正規形に分類される正規形は必ずしも必要とはされないが、複雑な要件が存在する場合には意識するべきとされる。

[主キー](#主キー)以外の属性が他の[候補キー](#候補キー)に従属している状態を排除する。

これは`𝑋 → 𝑌`という関係性があるときに、𝑋 が主キーではない状態を排除することを指す。

つまり、ボイスーコッド正規形においては`𝑋 → 𝑌`という関係従属があるときは`𝑋`が主キーでなければならない。

主キーになりうる属性が主キー以外の列に存在している状態とも表現できる。

ボイスーコッド正規形でない場合、主キーとして扱われていない 𝑋 に対して変更や削除があった際に、複数のレコードに存在しているかもしれない**全て**の 𝑋 に対しての更新が必要になる（処理負担が増える）。

ただし、 𝑋 が複合キーのうちの一つである場合、不可逆的な分解になってしまうため注意が必要。

:::note info
ボイス・コッド正規系は不可逆分解になることがある
:::

## 第 4 正規形

多値従属性を排除すること。

第 4 正規形は可逆的なので、結合によって元の状態に戻す事ができる。

### 多値従属性

属性 𝑋 に対して、属性 𝑌 と属性 𝑍 がそれぞれ独立して決まる関係性。属性 𝑌 と属性 𝑍 の間には関係性が存在しない。

`𝑋 →→ 𝑌 | 𝑍`

## 第 5 正規形

結合従属性を排除すること。

多対多の関係が頻繁に発生する場合に有用。



# SQL
Structured Query Language = 構造化問合せ言語

SQLには一部のベンダで独自の文法が用意されている。これと対比させて、標準規格に準拠したものを**標準SQL**と言う。

## DDL
Data Definition Language

データベースを定義するためのSQL。

テーブル、ビュー、インデックス作成に利用される。

### `CREATE DATABASE`

データベースを作成する。

```sql:CREATE DATABASE
CREATE DATABASE database_name;
```

### `DROP`

データベースを削除する。

```sql:DROP
DROP DATABASE database_name;
```

### `CREATE TABLE`

テーブルを作成する。

```sql:CREATE TABLE
CREATE TABLE table_name (
    column_1 data_type [constraint],
    column_2 data_type [constraint],
    column_3 data_type [constraint],
   ....
);
```

`constraint`（[制約](#制約)）には`PRIMARY KEY`、`NOT NULL`などが指定できる。

### `ALTER`

テーブルに変更を加える。

カラムを追加する場合は `ADD` と合わせて使用する。

```sql:ALTER(カラムの追加)
ALTER TABLE table_name
ADD column_name datatype;
```

カラムを削除する場合は、`DROP` を合わせて使用する。

```sql:ALTER(カラムの削除)
ALTER TABLE table_name
DROP COLUMN column_name;
```

カラム名を変更する場合

```sql:ALTER(カラム名の変更)
ALTER TABLE table_name
RENAME COLUMN old_name to new_name;
```


### `CREATE VIEW`

[ビュー](#ビュー)を作成する。

```sql:CREATE VIEW
CREATE VIEW view_name (column_1, column_2, ...) AS
SELECT column_1, column_2, ...
FROM table_name
WHERE condition;
```

作成したビューは仮想テーブルであるため、次のようにして参照することができる。

```sql:ビューを参照する
SELECT * FROM view_name;
```

:::note info
`CREATE TABLE` では `AS SELECT` を使用する
:::


### `CREATE INDEX`

[インデックス](#インデックス)を作成する。

```sql:CREATE INDEX
CREATE INDEX index_name
ON table_name (column_1, column_2, ...);
```

### `CREATE ROLE`

[ロール](#ロール)を作成する。

```sql:CREATE ROLE
CREATE ROLE role_name;
```

### `CREATE TRRIGER`

[トリガー](#トリガー)を作成する。

```sql:CREATE TRRIGER
CREATE TRIGGER trigger_name
AFTER target_operation
ON table_name
FOR EACH ROW
BEGIN
    action
END;
```

`AFTER` ではなく `BEFORE` も使用可。

`target_operation`（トリガーの対象とする操作）には`INSERT`、`UPDATE`、`DELETE`などが指定できる。

`FOR EACH ROW`は全ての行に対して処理が実行されるようにするためのもの。

### `DELARE CURSOR`

[カーソル](#カーソル)を宣言する。

データベースやテーブルとは異なり、カーソルは永続的なものではないため、`CREATE` ではなく `DECLARE` を使用する。

```sql:DELARE CURSOR
DECLARE cursor_name FOR
SELECT column_1, column_2, ...
FROM table_name;
```

:::note info
`DELARE CURSOR` では `FOR SELECT` を使用する
:::



## DCL
Data Control Language

データベースのデータに対するアクセス制御を行うためのSQL。

他にも[トランザクション](#トランザクション)の開始、終了、アクセス権の制御などを行うために利用される。

### `GRANT`

```sql:GRANT 
GRANT privilege
ON table_name
TO user_name;
```

`privilege`（権限）には、`ALL PRIVILEGES`、`SELECT`、`INSERT`、`DELETE`などが指定できる。

`user_name`には、ユーザ名の他に[ロール](#create-role)も指定できる。

### `START TRANSACTION`

トランザクションの開始を示す構文。

```sql:TRANSACTION
START TRANSACTION;
```

トランザクションの設定において、他のトランザクションとどのように隔離されるかの定義を**分離レベル**と言う。

```sql:TRANSACTION（分離レベル）
START TRANSACTION isolation_level;
```

`isonlation_level`（[分離レベル](#独立性--isolation)）には以下の4つのいずれかを指定することができる。

- `READ UNCOMMITED`
- `READ COMMITED`
- `REPEATABLE READ`
- `SERIALIZABLE`

### `COMMIT`

トランザクション内のすべての操作が成功した場合、データベースへの変更内容を確定させるための構文。

```sql:COMMIT
COMMIT;
```

### `ROLLBACK`

トランザクション内でエラーが発生した場合、トランザクション内で行なった変更内容をキャンセルするための構文。

```sql:ROLLBACK
ROLLBACK;
```

## DML
Data Manipulation Language
Manipulation = 操作

データベースのデータを操作するためのSQL。レコードの追加、更新、削除を行うために利用される。

### `SELECT`

```sql:SELECT
SELECT column_1, column_2, ...
FROM table_name;
```

`DUSTINCT` を使用することで重複を排除することができる。

```sql:SELECT
SELECT DINSTINCT column_1, column_2, ...
FROM table_name;
```

また、`column_1` の部分には[集約関数](#集約関数)も使用できる。

### `INSERT`

```sql:INSERT
INSERT INTO table_name (column_1, column_2, column_3, ...)
VALUES (value_1, value_2, value_3, ...);
```

### `UPDATE`

```sql:UPDATE
UPDATE table_name
SET column_1 = value_1, column_2 = value_2, ...
WHERE condition;
```

### `DELETE`

```sql:DELETE
DELETE FROM table_name
WHERE condition;
```

# 関係演算
Relational Algebra
algebra=代数

関係（リレーション、テーブル）に対しする操作やクエリのこと。関係演算を使用することで、リレーションから必要な情報だけを抽出したり、組み合わせて新たな関係を導くことができる。

## 和 / `UNION`
Union

2つのリレーションの全ての行を結合する操作。**OR演算**とも呼ばれる。

`𝑅 ∪ 𝑆` で表現され、リレーション 𝑅 と 𝑆 の全ての行を結合することを意味する。

```sql:UNION
SELECT column_name FROM table_1
UNION [ALL]
SELECT column_name FROM table_2;
```

`ALL`をつけることで重複した行も複数抽出される。

[結合](#結合--join)と似ているが、結合ではカラムが増えるのに対して、`UNION` は和演算なので `table_2` のレコード分が `table_1` の下に追加される。


## 差 / `EXCEPT`
Difference

リレーションから別のリレーションとの共通行を除外する操作。

`R − S`で表現される。

```sql:EXCEPT
SELECT column_name FROM table_1
EXCEPT [ALL]
SELECT column_name FROM table_2;
```

`table_1` に存在するが、`table_2` には存在しない行を返す。

`ALL`をつけることで重複した行もそのまま複数抽出される。（Oracle DB では `EXCEPT` の代わりに `MINUS` を使用する。）

`table_1` と `table_2` の順番を変えると結果が変わることに注意。

:::note info
差は「順番」によって結果が変わる
:::


## 積 / `INTERSECT`
Intersection

2つのリレーションの共通する行を抽出する操作。交差、`AND`演算とも言う。

`R ∩ S` で表現する。

```sql:INTERSECT
SELECT column_name FROM table_1
INTERSECT [ALL]
SELECT column_name FROM table_2;
```

`ALL`をつけることで重複した行もそのまま複数抽出される。

## 直積 / `CROSS JOIN`
Direct Product、Cartesian Product

2つのリレーションの全ての行を掛け合わせる操作。

`𝑅 × 𝑆` で表現する。

```sql:CROSS JOIN
SELECT *
FROM table_1
CROSS JOIN table_2;
```

## 射影
Projection

リレーションから特定の列（属性）を抽出する操作。

## 選択
Selection

リレーションから特定の行（タプル）を抽出する操作。

## 商
Division

特定の属性の値の組み合わせが全て揃っている行を抽出する操作。`R ÷ S`で表現する。S を全て含む R の列を抽出する。

## 結合 / `JOIN`
Join

2つのリレーションを結合し、新しいリレーションを生成する操作。

`ON`と合わせて利用する。結合を行う双方のカラム名が同じ場合、`USING` で使うことでテーブル名を省略できる。

```sql:USING
FROM A JOIN B USING common_column
```

[外部結合](#外部結合--outer-join`)でないもの（`JOIN`）は、内部結合 `INNER JOIN`（デフォルト）になる。

:::note info
`JOIN` は `INNER JOIN` のこと
:::


### θ結合
θ（シータ)

2つのリレーション間を任意の条件（θ）に基づいて結合する操作。


| 比較演算子（θ） |  |
|:-:|:-:|
| `=` | 等しい |
| `<>` | 等しくない |
| `<` | 小なり |
| `>` | 大なり |
| `<=` | 以下 |
| `>=` | 以上 |


```sql:INNER JOIN
SELECT column_name
FROM table_1
JOIN table_2 ON table_1.column_name > table_2.column_name;
```

### 等結合
θが `=` であるθ結合を特に**等結合**と言う。

```sql:等結合
SELECT column_name
FROM table_1
JOIN table_2 ON table_1.column_name = table_2.column_name;
```

### 自然結合 / `NATURAL JOIN`

```sql:等結合
SELECT column_name
FROM table_1
JOIN table_2 ON table_1.column_name = table_2.column_name;
```

と言う[等結合](#等結合)を実行した時に、重複して表示されるカラム `table_1.column_name` と `table_2.column_name` の一方を排除したもの。

```sql:NATURAL JOIN
SELECT column_name
FROM table_1
NATURAL JOIN table_2;
```

[`USING`](#結合--join)を使った場合と同じ結果を得ることができる。

### 外部結合 / `OUTER JOIN`

2つのリレーション間に、一致するものがない場合でも抽出操作を行う結合のこと。

#### 左外部結合 / `LEFT OUTER JOIN`

リレーション R と S のうち、左側の R の行は全て抽出する結合操作。R に対応する S の行がない場合、`NULL`が挿入される。

```sql:LEFT OUTER JOIN
SELECT column_name
FROM table_left
LEFT OUTER JOIN table_right
ON table_left.column_name = table_right.column_name;
```

#### 右外部結合 / `RIGHT OUTER JOIN`

リレーション R と S のうち、右側の S の行は全て抽出する結合操作。S に対応する R の行がない場合、`NULL`が挿入される。

```sql:RIGHT OUTER JOIN
SELECT column_name
FROM table_left
RIGHT OUTER JOIN table_right
ON table_left.column_name = table_right.column_name;
```

#### 外部完全結合 / `FULL OUTER JOIN`

リレーション R と S のうち、どちらかに存在する行は全て抽出する操作。対応する列が存在しない場合、`NULL`が挿入される。

```sql:FULL OUTER JOIN
SELECT column_name
FROM table_left
FULL OUTER JOIN table_right
ON table_left.column_name = table_right.column_name;
```

### 内部結合 / `INNER JOIN`

2つのリレーション間で、一致するもののみを抽出する操作のこと。

```sql:INNER JOIN
SELECT column_name
FROM table_1
INNER JOIN table_2
ON table_1.column_name = table_2.column_name;
```

# その他のSQL

## 集約関数

集計関数とも呼ばれる。

| 集約関数 | 説明 |
|:-:|:-:|
| `SUM()` | 合計 |
| `MAX()` | 最大値 |
| `MIN()` | 最小値 |
| `AVG` | 平均値 |
| `COUNT()` | レコード数 |
| `COUNT(*)` | 全レコード数 |


## `GROUP BY`

特定の列に基づいてグループ化を行うための構文。

```sql:GROUP BY
SELECT column_name, 集約関数
FROM table_name
WHERE condition
GROUP BY column_name;
```

複数のカラムの組み合わせをグループ化のキーとすることもできる。

```sql:GROUP BY
GROUP BY column_name_1, column_name_2, column_name_3
```

とすると、`(column_namne_1, column_namne_2, column_namne_3)` の組み合わせによる単位で一致するレコードがグループ化される。

グループ化を行なった場合、「グループ化を行なったカラム」もしくは「[集約関数](#集約関数)」しか表示させることはできない。

例えば、以下は表示できる。

```sql
SELECT 商品番号, SUM(売上額)
FROM 売上
GROUP BY 商品番号;
```

一方で商品番号でグループ化した時、同じ商品番号の売上額は複数存在することもあり、その場合どの値を表示すべきかがわからないため、以下はエラーが発生する。

```sql
SELECT 商品番号, 売上額
FROM 売上
GROUP BY 商品番号;
```

エラーを発生させないためには、グループ化の条件を以下のようにする必要がある（この例では、商品番号と売上額をグループ化して表示する目的は特に考えないこととする）。

```sql
SELECT 商品番号, 売上額
FROM 売上
GROUP BY 商品番号, 売上額;
```

:::note info
`GROUP BY` でグループ化を行なった場合、「グループ化を行なったカラム」もしくは「[集約関数](#集約関数)」しか表示させることはできない
:::


### `HAVING`

[`GROUP BY`](#group-by)の結果に検索条件をつける。

```sql:HAVING
SELECT column_name
FROM table_name
GROUP BY column_name
HAVING condition;
```

## `CASE`

SQLで条件分岐を行うための構文。

特定の条件に応じて異なる値を返したり、処理を分岐させることができる。

シンプルな構文と、高度な構文の2種類がある。

```sql:CASE（シンプル版）
CASE column_1
    WHEN value_1 THEN result_1
    WHEN value_2 THEN result_2
    WHEN value_N THEN result_N
    ELSE result
END;
```

```sql:CASE（高度）
CASE
    WHEN condition_1 THEN result_1
    WHEN condition_2 THEN result_2
    WHEN condition_N THEN result_N
    ELSE result
END;
```

## `COALESCE`
coalesce = 合体する、融合する

欠損値をデフォルト値に置き換えるための構文。データ分析を行う際に、 `NULL` なら `0` として扱いたい場合などに利用する。

```sql:COALESCE
COALESCE(expression, default_value)
```

例えば、電話番号が`NULL`の時にメールアドレスを返すようにする。

```sql:COALESCE
SELECT column_1,
       COALESCE(phone, mail_address) AS contact
FROM table_1;
```

## `CONCAT`

文字列を連結するための構文。

```sql:CONCAT
CONCAT(column_1, column_2)
```

## ウィンドウ関数

SQLでデータの集計や分析を、より柔軟に行うために利用される高度な関数。

複雑な処理を行いたい場合に利用することで、副問合せを複数組み合わせるなどの複雑な記述不要になる。

`OVER`句が使用される。

| ウィンドウ関数 | 説明 |
|:-|:-|
| `ROW_NUMBER()` | 各行に対して、一意の行番号を付与する |
| `RANK()` | 並べ替え順序に基づくランクを付与する |
| `DENSE_RANK()` | 同順位がある場合、ランクを飛ばさずに連続して付与する |
| `LAG(column_name, n)` | n行だけ前にある行の値を参照 |
| `LEAD(column_name, n)` | n行だけ後ろにある行の値を参照 |
| `SUM()` | 合計 |
| `AVG()` | 平均 |
| `MAX()` | 最大値 |
| `MIN()` | 最小値 |
| `COUNT()` | 行数 |

`SUM()`、`AVG()`、`MAX()`、`MIN()`、`COUNT()` は、[集約関数](#集約関数)がウィンドウ関数として発展したもの。


```sql:ウィンドウ関数
ウィンドウ関数() OVER (
    [PARTITION BY grouping_column]
    [ORDER BY ordering_column]
    [frame_range]
)
```

`PARTITION BY` では、データをグループに分割するための列を指定する（[`GROUP BY`](#group-by) と同様）。

`ORDER BY` では、並べ替えを行う列を指定する。

`frame_range` には、 `ROWS` または `RANGE` を使ってウィンドウ関数が計算を行う範囲を指定する。

| `frame_range` | 説明 |
|:-|:-|
| `CURRENT ROW` | 現在の行 |
| `n PRECEDING` | `ROW` : 現在行から`n`行前<br>`RANGE` : `n`値前  |
| `n FOLLOWING` | `ROW` : 現在行から`n`行後<br>`RANGE` : `n`値後  |
| `UNBOUNDED PRECEDING` | `ウインドウの先頭行` |
| `UNBOUNDED FOLLOWING` | `ウィンドウの末尾行` |

以下は「2行前から現在の行まで」を表す。

```sql:ROWS
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
```

## 副問合せ

`SELECT`文の中で、入れ子にした`SELECT`文。

外側の`SELECT`文の方を**主問合せ**という。

### 相関副問合せ

副問合せには主問合せと相関するものと相関しないものがあり、相関するものを特に**相関副問合せ**という。

相関しない副問合せは「副問合せ▶️主問合せ」の順に単純に実行されるのに対して、相関副問合せは「主問合せから1行づつ値をもらいながら副問合せが複数回繰り返されながら実行」というように実行の形態が大きく異なる。そのため相関副問合わせは、相関しない副問合せと比べて実行負荷が非常に高い。

:::note info
「相関副問合せ」は「副問合せ」の一つだが、実行形態が大きく異なる
:::

#### `EXISTS`

相関副問い合わせとして利用される代表的なSQL文に `EXISTS` がある。

```sql:EXISTS
SELECT column_name
FROM table_name_1
WHERE EXISTS
(SELECT column_name FROM table_name_2 WHERE condition);
```

副問合せ中の `condition` に `tabe_name_1` のカラムを使用した場合、主問合せと副問合せが相関することになる。

### `WITH`

副問合せにおいて、一時的な仮想テーブルを作成することで複雑なクエリを読みやすくするための構文。

```sql:WITH
WITH virtual_table_name (column_name)
AS (
    SELECT column_name
    FROM real_table_name
    WHERE condition;
);
```

## SQLが実行される仕組み

![SQL.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/add5afbc-ed0d-9fa4-1ae4-8a7081f921ef.png)

### Parser
文法チェックが実行される。

### Optimizer
SQLのアクセスパスが決定される。最適化。

### Catalog Manager
統計情報の照会を受け付ける。データへのアクセスプランを決定して回答する。




# 障害管理

## リストアとリカバリ

バックアップしておいたファイルをDBに戻す作業を**リストア**と呼び、バックアップ実施後に作成されたトランザクションログを適用してバックアップ時から障害発生時までの状態に戻す作業を**リカバリ**と呼ぶ。

## バックアップ

### フルバックアップ
- 全てのデータを対象とするため、バックアップを取得するための時間（**バックアップウィンドウ**）が長い
- データの整合性を保ちながらバックアップを取得するには、バックアップ中はサービスを停止させる必要がある
- バックアップデータのサイズが膨大

 ### 差分バックアップ
- フルバックアップと組み合わせて使用
- フルバックアップを定期的に行い、次回のフルバックアップまでは差分バックアップを取得する
- 実際にはDBへの操作を記録したログをバックアップする（復元時には過去の操作をもう一度行えば良い）
- バックアップデータ量が少なくて済む

### 増分バックアップ
- 差分バックアップをさらに効率的にしたもの
- 差分バックアップはフルバックアップとの差分を対象としているのに対して、増分バックアップは前回の差分バックアップとの差分を対象とするため、さらに少ないデータ量で済む
- 効率的な保存方法なのに対して、復元作業が複雑化するというデメリットがある

## フォールトトレラント
Fault = 問題、誤り、障害
Tolerant = 受け入れる、耐える、我慢する

障害が起こっても機能維持する能力を持たせる設計手法。部分的に障害が発生してもシステム全体としては停止することなく稼働し続ける。

冗長化、バックアップなどにより実現される。

## フォールトアボイダンス
Fault = 問題、誤り、障害
Avoidance = 避ける、回避する

障害が発生する可能性を可能な限り取り除くことで、障害自体が発生しないようにする設計手法。

障害を予防するためのメンテナンスや設計の最適化により実現する。

## フェールセーフ
Fail = 失敗する、故障する
Safe = 安全

障害が発生しても、危機的状況には陥らず、安全な状態を維持するように設計すること。障害が新たな問題を発生させないようにする。

電源が切れたら自動的にシャットダウンする、障害児は赤信号を点灯させる、など。

## フェールソフト
Fail = 失敗する、故障する
Soft = 軽度の、柔らかな、穏やかな

[フォールトトレラント](#フォールトトレラント)と似ているが、部分的な障害が発生した場合に、システム全体としては稼働停止せず、部分的な機能の稼働だけは維持し続けるようにする設計手法。

## フールプルーフ
Fool = おろなもの、間違いを犯しやすい人
Proof = 耐える、防ぐ

ユーザが意図的ではなくても、誤った操作をした際に障害を発生させない、もしくは誤操作自体を行わせないようにする設計手法。

## フォールトマスキング
Fault = 問題、誤り、障害
Masking = 隠す、覆い隠す

システム内部で障害を検出した際に、ユーザや他のシステムからは見えなくする、外部に影響を与えないようにする設計手法。

システムの冗長化によって実現する。例えば、計算機能を3つのコンポーネントに行わせ、1つが誤った結果を出してもその他の2つのコンポーネントによってシステム全体としては正しい結果が出る、など。


# 用語

## テーブル

テーブルとはある共通点を持つレコードの集合であるため、必ず複数名詞で表現することができる（Item**s**、Order**s**など）。

:::note info
複数名詞で表現できないテーブルは、どこかに間違えが潜んでいる可能性が高いと考えた方が良い。
:::

## ビュー

テーブルのデータを表示する仮想的なテーブルを**ビュー**と言う。

ビューは実際のデータを持たず、元となるテーブルからデータを取得して表示したものを指す。基のテーブルを**基底テーブル**と言う。

基底テーブルのようにデータは保持せず、参照のたびにクエリを実行して常に動的にデータを取得する。そのため、ビューでは常に最新のデータが取得できる。

他にも、ユーザに対して複雑なクエリやテーブルの構造を隠蔽するためにも利用される。基底テーブルは、あくまでもユーザに対して隠蔽されるのであり、エンジニアは基底テーブルの存在を無視することはできない。多段的なビューがある場合などは、段の数だけ内部で`SELECT`文が階層的に実行されていて、濫用するとパフォーマンスに悪影響を及ぼす。

また、基底テーブルに公開したくないカラムが含まれる場合、そのカラムを除いたビューを用意して、ビューのみを公開するなどと言う利用方法もある。

## カーソル

クエリの結果として返される複数の行を一行ずつ処理するための仕組み。

特にプログラムやスクリプト内で複数行のデータを逐次処理する際に使用される。

基本的には以下の流れで操作を行う。

| 順番 | コマンド | 説明 |
|:-:|:-:|:-|
| 1 | `DECLARE` | 宣言<br>SQL文で取得するデータを指定してカーソルを宣言<br>`DECLARE cursor_name CURAOR FOR SELECT...` |
| 2 | `OPEN` | オープン<br>カーソルを開いて、SQLクエリを実行<br>`OPEN cursor_name` |
| 3 | `FETCH INTO` | フェッチ<br>カーソルから一行ずつデータを取得<br>取得したデータは変数（`@variable_name`）に格納される<br>`FETCH cursor_name INTO : @variable_name` |
| 4 | `CLOSE` | クローズ<br>処理が終わったら、カーソルを閉じてリソースを解放br>`CLOSE cursor_name` |

## ロール

ユーザーやグループに特定の権限やアクセス許可を付与するための概念を**ロール**と言う。

ロールを使用することにより、個々のユーザに対して直接権限を設定するのではなく、権限の設定を行なったロールを各ユーザに割り当てることが可能になる。

## トリガー

特定のデータベース操作（`INSERT`、`UPDATE`、`DELETE`など）をきっかけにして、自動的に発生させるアクションや処理を**トリガー**と言う。

## キー

関係においてレコード（行）を一意に識別するための属性、もしくは属性の集合を**キー**という。

### キーを文字列型にする際の注意点

キーとなる属性を文字列型にする場合、可変長文字列にしてしまうと、同じ属性値を指して入力された値がひらがな・カタカナ・漢字表記の違いやスペースの有り無しによって微妙に変わってしまい、異なるキーとして登録されるという事態が発生する。

そのためキーに文字列型を使用する場合は、何らかのコードやIDなどの**固定長文字列**を使用するようにする。

また、基本的にキーは不変の値（コード）が望ましい。

:::note info
変更の可能性がある情報をキーとして使用しない。
:::

### スーパーキー
レコード（行）を一意に識別する事ができる属性（列）や属性の集合。

レコードを一意に識別さえできれば良いため、識別するために不要な属性を含んでも良い。

### 候補キー

1. レコード（行）を一意に識別する事ができる属性や属性の集合
2. 1のうち、極小のもの

上記2つの条件を満たす属性（列）や属性の集合のこと。

条件を満たしていれば、レコードごとに異なる候補キーであっても良い。

[主キー](#主キー)の候補となるキーのこと。

### 主キー
プライマリキー、ユニークキー（製品によって呼び名が微妙に違う）。

[一意性制約](#一意性制約)と[NOT NULL 制約](#not-null-制約)を併せ持つ（[主キー制約](#主キー制約)）。

レコードを識別するために余計な属性は含まないが、だからと言って**一つの属性である必要はない**（複数の属性の組み合わせが主キーであることもある。この場合、**複合キー**と呼ぶ）

### 複合キー

[主キー](#主キー)、[外部キー](#外部キー)が２つ以上の属性で構成される場合のキー。

### 代理キー
[候補キー](#候補キー)のうち、主キーに選ばれなかった属性。

### 外部キー
他のテーブルの主キーを参照するために使用される属性あるいは属性の集合。

### サロゲートキー
代理キー（surrogate=代理、身代わり）。

通し番号のような、人工的に作られた情報をキーにしたもの。

要件上、自然キーが存在せずやむを得ず使用される。

### 自然キー
ナチュラルキー。

人工的に作られたサロゲートキーに対して、自然に存在する情報をキーにしたもの。


## シーケンスオブジェクト
単にシーケンスやシーケンスジェネレータとも呼ばれる。

一意な連続した数値を生成するためのオブジェクトで、多くのDB製品で`CREATE SEQUENCE`などのSQLによって作成される。

初期値、増分（ステップ）、最大値、最小値、サイクル（再利用）などを設定してカスタマイズする事ができる。

また、テーブルとは独立して存在しているため、複数のテーブル間で共有する事ができる。

似たものに、オートナンバリング機能がある。

ただし、オートナンバリング機能は、
SQL Server : `IDENTITY`型
PostgreSQL : `SERIAL`型
MySQL : `AUTO_INCREMENT`型
というようにDB製品間で互換性がないため、シーケンスオブジェクトの方が柔軟性がある。

## CRUD分析

システムがどのようにデータを操作するかを整理し、設計の品質を高めるための手法。

- **C**reate : 作成 : `INSERT`
- **R**ead : 参照 : `SELECT`
- **U**pdate : 更新 : `UPDATE`
- **D**elete : 削除 : `DELETE`

|| 機能 A | 機能 B | 機能 C |
|:-:|:-:|:-:|:-:|
| **テーブル A** | RU | R |  |
| **テーブル B** |  | CRU |  |
| **テーブル C** | C | C | CRD |

システムが**機能ごとに各テーブルに対してどのような操作を行うか**が明確になり、データ操作のパターンが整理されることで、設計の一貫性を保つことができる。

例えば、「作成」されていないデータを「参照」「更新」「削除」しようとしていないかをチェックしたり、また特定のテーブルに対する処置の偏り（アクセス数）がないかを把握することができる。

## デシジョンテーブル
Decision Table
決定表

特に複雑なビジネスルールや条件付きのロジックを整理するためのツール。複数の「条件」とそれに対応する「アクション」を表形式でまとめることで、条件に基づいた決定が理解しやすくなる。

- 条件
    - 「Y」（Yes）、「N」（No）等で表現される
- 処理
    - 「X」（処理が必要）、「-」（処理が不要）等で表現される

| **区分 A** | 1 | 1 | 2 | 2 |
|:-:|:-:|:-:|:-:|:-:|
| **区分 B** | **1** | **2** | **1** | **2** |
| **テーブル A** | **X** | - | - | - |
| **テーブル B** | - | - | - | **X** |








# 参考
- [達人に学ぶDB設計 徹底指南書](https://amzn.asia/d/hRkz5aZ)
- [徹底攻略 データベーススペシャリスト教科書 令和6年度](https://amzn.asia/d/0j40i6m5)
- [キタミ式イラストIT塾 応用情報技術者](https://amzn.asia/d/3WJSC0N)
- [W3Schools Online Web Tutorials](https://www.w3schools.com/)
- [東大入試のノリで解いてデータベーススペシャリストを攻略した話](https://qiita.com/konbraphat51/items/9f5350448b54d802675f)
- [情報処理教科書 データベーススペシャリスト](https://amzn.asia/d/f4PXg1K)
- [情報処理試験まとめwiki](https://shiken.wiki.fc2.com/m/wiki/DB)