【初心者向け🔰】DB の「スキーマ」「ORM」「マイグレーション」とは何か

## 概要
データベース（DB）に関する勉強をしていると、「テーブル」や「カラム」などの基本的な言葉以外に、以下のような言葉を聞く機会が出てくると思います。
「ORM」「O/Rマッパー（オーアールマッパー）」「スキーマ」「マイグレーション」

もしくは、Ruby on Rails などのアプリケーションフレームワークを利用すると、DB 周りの処理で同様の単語が出てくるでしょう。

色んな記事で説明されていますが、イマイチわかりやすいものが少ないと感じたため、これらが何を意味するのかを、初心者向けに超ざっくりとまとめます。

## スキーマとは
「スキーマ」とは、一般的に **「構造」** を意味する単語で、これはプログラミングの専門用語ではない。
一言に「スキーマ」と言っても、具体的に **"何に"** 対する構造を指しているかで意味が変わる。今回は **「DB のスキーマ」** について説明する。

DB における「スキーマ」とは、DB のテーブルやカラム等の構造定義のこと。つまり「何ていう名前のテーブルがあるのか」「そのテーブルにはどんなカラムがあるのか」「他のテーブルとどんな関係があるのか」などの構造のことを「スキーマ」と呼んでいる。

例えば、**「User という名前のテーブルがある」「User テーブルには id, name, email, age というカラムがある」「id は数値である、name は文字列である」「User テーブルのインデックスは id である」** などをまとめた情報が、スキーマである。

また、**「User テーブルに登録されている値（レコード）」** は、構造ではなくデータそのものなので、これはスキーマではない。

つまり、「テーブルを作成/削除する」「テーブルのカラムを追加/削除する」「カラムのデータ型を変更する」「インデックスを追加/削除する」などの行為は、**"スキーマの変更"** と呼べる。

## ORM とは
「ORM」とは、**"Object-relational mapping"** の略で **"O/R Mapping"** とも表される。日本語では **「オブジェクト関係マッピング」** または **「オブジェクト関連マッピング」** と訳す。
Wikipedia 等の一般的な説明では、『データベースとオブジェクト指向プログラミング言語の間の、非互換なデータを変換するプログラミング技法である。』とあるが、これではわかりにくいので、もう簡単に少し噛み砕く。

### 前提
まず、「（アプリケーションの）バックエンド」と「DB」の連携を考える場合、そもそもバックエンドはどんな言語/フレームワークを利用するのか？（例： Java/Spring なのか、Ruby/Rails なのか、JavaScript/Node.js なのか）
そして、DB は具体的に何を使うのか？（例： MySQL なのか、PostgreSQL なのか、Oracle なのか）、設計によって様々なパターンがある。

### 例えば
あるプロジェクトで、**アプリ開発には Ruby on Rails** を使い、**DB には MySQL を採用した** とする。しかし、その後に事情があって、**使用する DB は MySQL から PostgreSQL に変更することになった** とする。

この場合、DB のスキーマやデータそのものは変わらない。しかし、DB の仕様（例： 文字列/数値型/日付型などのデータ型、表現方法、DB 接続方法など）は変わるので、Ruby で DB の仕様に合わせて処理の書き方も修正しなければならない。

もし、ある決まった書き方をすれば、MySQL でも PostgreSQL でも問題なく動く SQL を自動で発行してくれるような便利なプログラムがあれば、それを利用することで、バックエンドの Ruby の処理の書き方を、わざわざ DB に合わせて修正する必要はなくなる。

### つまり ORM  とは
DB の SQL を書かなくても、プログラム側からより簡単に SQL の発行をできる仲介プログラム。
今回の例で言うと、DB が MySQL から PostgreSQL に変わっても、Ruby の書き方を変更しなくて済むように、 DB との仲介をしてくれる技術のこと。

これを実現するツールは「ORM ツール」「O/R マッパー」などとも呼ばれる。
ORM ツールは世の中に沢山あり、ツールによって使い方やお作法は異なる。お作法に則った書き方で、データの検索・登録・更新などの処理を書けば、自動で DB に合わせて SELECT や UPDATE などの SQL を発行・処理してくれる仕組みになっている。

「DB のスキーマ」を定義するファイル ＝ **スキーマ定義ファイル** を用意し、それを利用すれば、どんな DB でも良い感じに処理を仲介してくれて、データの検索や登録・更新などが簡単になる技術。

例えば、**「"User" テーブルから id =5 のレコードを検索し、レコードの中の name を取得する」** という処理を Ruby on Rails で書くときに、ORM が仲介してくれれば、DB が MySQL でも PostgreSQL でも処理の書き方や結果が変わらないということである。

### ORM の目的
- プログラムと DB の関係を疎結合にすること
- DB 処理の書き方を簡単にすること
  - ただし、複雑な SQL は書けない（その時は SQL をそのまま渡す関数を使う）
  - また、ORM ツール特有の書き方を覚える必要がある

### ORM ツールの例
Ruby on Rails のように、アプリケーションフレームワークに ORM 機能を含んだ技術もあれば、下記の様な ORM 専用の単体ツールもある。
Flyway（Java）、Prisma（TypeScript）、TypeORM（TypeScript）、LiquiBase（Java）、golang-migrate（Go）など。

### スキーマ定義ファイルの例
Node.js/TypeScript で利用できる ORMツール「Prisma」では、`schema.prisma` というスキーマ定義ファイルを用意し、以下の様に中身を設定する。
※ 当然、フレームワークやツールによってスキーマ定義ファイルのファイル名や書き方は変わる。

```js:schema.prisma
// 使用する DB の接続設定
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

// DB からプログラムにマッピングするツールの指定
generator client {
  provider = "prisma-client-js"
}

// ここ以降に、DB のテーブル定義を書いていく 👇

// "ユーザ" テーブル定義 (カラム名、主キーやユニークキー、データ型を定義)
model User {
  id    Int             @id @default(autoincrement())
  email_address String  @unique
  name  String?
}
```
こういった「スキーマ定義ファイル」があることで、DB の構造を抽象化してくれ、開発者は「何の DB を使っているのか」をあまり意識しなくて済む。

## マイグレーションとは
「マイグレーション (Migration)」とは、**「移行」** を意味する英単語。これは DB に関する専門用語ではなく、"移行" を意味するなら別の場面でも使われることがある。

例えば、「Java で書かれたシステムを、Ruby で書いたものに変更するプロジェクト」のことを **"Java から Ruby へのマイグレーション案件"** と表現することがある。

### DB のマイグレーションとは
DB における **マイグレーション** とは、「DB の変更内容をファイルに記録し、その内容を実行して DB のスキーマを更新していく手法」のこと。

具体的には、スキーマの変更を記録したファイル ＝ **「マイグレーションファイル」** （多くの場合は SQL が書かれた `.sql` ファイル）を用意し、中に書かれた SQL を順番に実行することで、DB のスキーマを変更していくこと。

例えば、**「User テーブルを作成する」「User テーブルにカラムを追加する」「別のテーブルを作成し、User テーブルのあるカラムと外部キーで連携する」** などのスキーマ変更をするためのファイルを用意し、既に存在するデータが消えないようなスキーマ変更の SQL を、それぞれに書いていく。
それらファイルを、マイグレーションを行うコマンドを実行することによって、順番に SQL を実行していく。

### マイグレーションファイルはいつ作るのか
一度に複数のマイグレーションファイルを作成しているのではなく、後々で決まった仕様変更などのタイミングに１つファイルが作られるイメージ。

つまり、「こういうテーブルが必要だ」→（数日後）→「やっぱり、このテーブルはこうした方が良い」→（数時間後）→「あのテーブルとこのテーブルは外部キーで繋げた方が良い」のような仕様変更のタイミングで、都度マイグレーションファイルを作るということ。

多くの場合は、マイグレーションファイルのファイル名は「年月日」がわかるようなネーミングになっており、これによって変更履歴を確認することができる。
また、時系列にマイグレーションファイルを順次実行することで、DB を作り直す場合（ローカル環境構築時など）に、DB のスキーマを簡単に復元できる。

### スキーマ定義ファイルとは別である
マイグレーションは、あくまでスキーマ変更を行う SQL が書かれたファイルを時系列に実行することなので、DB のスキーマは変更するが、それを管理する「スキーマ定義ファイル」までは変更しない。
ただ、ツールやフレームワークによっては、マイグレーションを実行する度に、スキーマ定義ファイルも自動で最新化してくれる場合がある。自動で更新されない場合は、手動で更新する必要がある。

### マイグレーションの目的
- 既に存在するデータを維持しながら、スキーマを安全に変更する
- スキーマの変更履歴を管理する
  - ただし、時間経過でマイグレーションファイルが増え続ける問題があるため、どんなタイミングでファイルをどう整理するのかを考える必要がある。
- 万が一 DB が破損・消失しても、スキーマやアプリ動作に必要な最低限のデータをすぐに復元できるようにする
  - ただし、実際にマイグレーションを行う際には、必ずバックアップを取り、予期せぬ問題が発生してもデータを回復できるようにしておくことが重要。

マイグレーションは、通常はデータベースマネジメントシステム（DBMS）によってサポートされているが、マイグレーションを行うためのツールやライブラリも存在する。前述の ORM ツールの多くは、マイグレーション機能を持っている。

## リバースエンジニアリングとは
※ 「リバースエンジニアリング」という単語自体は、DB 領域専用の単語ではない。
既存の製品やソフトウェアからその構造、機能、動作原理を解析するプロセスのことを指す。これにより、その製品がどのように動作しているかを理解し、さらにはそれを再構築または改善することが可能になる。リバースエンジニアリングは様々な分野で応用されており、今回は DB のテーブル構築などの場合で使用されるケースにおいての用法を解説する。

マイグレーションとは逆に、既存の DB からスキーマ情報を抽出して、スキーマ定義ファイルを自動生成する方法は **「リバースエンジニアリング (Reverse Engineering)」** と呼ばれている。

マイグレーションは、マイグレーション内容に記載がない DB スキーマやデータを消失してしまうため、「ORM ツールは使いたいけど、既にある DB のスキーマやデータは変えたくない」という場合は、マイグレーションではなくリバースエンジニアリングを行う。

尚、全ての ORM ツールがこの機能を持っているわけではないので、マイグレーションとリバースエンジニアリングの両方に対応しているツールかを確認する必要がある。

## まとめ

|キーワード|意味|
|---|---|
|スキーマ|DB の構造そのものを指す（テーブルやカラムの構造）|
|スキーマ定義ファイル|DB スキーマをまとめて定義したファイル。ORM ツールによって書き方が違う|
|ORM|DB とプログラムの仲介をする便利技術。バックエンドの処理の書き方を一定に保つ|
|マイグレーション|DB スキーマを変更する SQL をファイルにまとめて管理する技術。ファイル数が膨らむ問題がある|
|リバースエンジニアリング|既存の DB からスキーマ定義ファイルを生成する技術|

以上、プログラミング学習の参考になれば幸いです🙏