はじめに
Webシステムや業務システムを開発していると、ほとんどの場合で「データベース」を扱うことになります。
ユーザー情報、商品情報、注文履歴、売上情報など、システムで利用するさまざまなデータを保存する場所としてデータベースは使われています。
そして、データベースを使ったシステムを開発するときに重要になるのが、『データベース設計(DB設計)』です。
「保存したいデータが決まったから、とりあえずテーブルを作ればいいのでは?」
と思うかもしれません。
小さなシステムであれば、それでも最初は動くことがあります。
しかし、システムの機能が増えたり、扱うデータが増えたりすると、
- 同じ情報がいろいろな場所に保存されている
- どのデータが正しいのかわからない
- データを更新するときに複数のテーブルを変更しなければならない
- 必要なデータを取得するSQLが非常に複雑になる
- データ件数が増えると急に処理が遅くなる
といった問題が発生しやすくなります。
こうした問題をできるだけ防ぐために行うのが、データベース設計です。
このシリーズでは、データベース設計を初めて学ぶ人でも理解できるように、基本的な考え方から順番に解説していきます。
第1回では、まず
『そもそもデータベース設計とは何をする作業なのか』
について見ていきます。
この記事の対象者
この記事は、次のような人を対象にしています。
- エンジニアとして開発をしているが、データベースについてあまり詳しくない人
- SQLを書いた経験はあるものの、テーブル設計をした経験が少ない人
- 既存のデータベースを使ったことはあるが、ゼロから設計したことがない人
- データベース設計を体系的に学び直したい人
SQLの基本的な知識があると理解しやすいですが、データベース設計の経験はなくても問題ありません。
データベースとは何か
まず、「データベース」とは何なのかを簡単に整理しておきましょう。
データベースとは、簡単に言えば
『大量のデータを整理して保存し、必要なときに検索・追加・更新・削除できるようにした仕組み』
です。
例えば、ECサイトであれば次のようなデータがあります。
- ユーザー
- 商品
- 注文
- 注文明細
- 支払い情報
- 配送先
これらの情報をデータベースに保存することで、
「このユーザーが過去に購入した商品を表示する」
「今月売れた商品のランキングを表示する」
「注文番号から配送先を調べる」
といった処理ができるようになります。
Webシステムでよく利用されるMySQL、PostgreSQL、SQL Server、Oracle Databaseなどは、こうしたデータを管理するためのデータベース管理システムです。
DB設計とは何を決める作業なのか
では、データベース設計では何を決めるのでしょうか。
簡単に言うと、
『システムで扱うデータを、どのような構造でデータベースに保存するのかを決める作業』
です。
例えば、ユーザーを管理するシステムを考えてみます。
保存したい情報として、
- ユーザーID
- 氏名
- メールアドレス
- 生年月日
- 登録日時
があるとします。
すると、次のようなテーブルを考えることができます。
users
+---------+--------------+
| column | 内容 |
+---------+--------------+
| id | ユーザーID |
| name | 氏名 |
| email | メールアドレス |
| birthday| 生年月日 |
| created_at | 登録日時 |
+---------+--------------+
ただし、DB設計で決めるのは「カラム名」だけではありません。
例えば、次のようなことも考える必要があります。
- どんなテーブルを作るか
- それぞれのテーブルにどんなカラムを持たせるか
- 各カラムにどのデータ型を使うか
- どのカラムを主キーにするか
- テーブル同士をどのように関連付けるか
- NULLを許可するか
- 重複を許可するか
- データを削除したときにどう扱うか
- 検索を速くするためにどこへインデックスを作るか
つまりDB設計とは、
『データをただ保存できるようにするだけではなく、正しく、安全に、扱いやすく保存する方法を考える作業』
だと言えます。
適当にテーブルを作ると何が起こるのか
では、特に設計を考えずにテーブルを作った場合、何が問題になるのでしょうか。
例えば、簡単な注文管理システムを考えてみます。
次のようなテーブルを作ったとします。
orders
+----------+------------+----------------------+------------+
| order_id | user_name | user_email | product |
+----------+------------+----------------------+------------+
| 1 | 山田太郎 | yamada@example.com | パソコン |
| 2 | 山田太郎 | yamada@example.com | マウス |
| 3 | 佐藤花子 | sato@example.com | キーボード |
+----------+------------+----------------------+------------+
一見すると問題なさそうです。
しかし、山田さんがメールアドレスを変更したらどうでしょう。
注文1と注文2の両方を修正する必要があります。
もし注文データが100件あれば、100件すべてを更新しなければなりません。
さらに、一部だけ更新し忘れると、
yamada@example.com
yamada-new@example.com
という2種類のメールアドレスが存在してしまいます。
すると、
『山田さんの正しいメールアドレスはどちらなのか』
が分からなくなります。
このように、同じ情報を何度も保存するとデータの不整合が発生しやすくなります。
そこで、通常はユーザー情報と注文情報を分けます。
users
+---------+------------+----------------------+
| user_id | user_name | user_email |
+---------+------------+----------------------+
| 1 | 山田太郎 | yamada@example.com |
+---------+------------+----------------------+
orders
+----------+---------+------------+
| order_id | user_id | product |
+----------+---------+------------+
| 1 | 1 | パソコン |
| 2 | 1 | マウス |
+----------+---------+------------+
こうしておけば、山田さんのメールアドレスはusersテーブルの1か所を変更するだけで済みます。
このように、
『どの情報を、どのテーブルに持たせるのか』
を考えることがDB設計では非常に重要になります。
「とりあえずExcel感覚で作る」と問題になりやすい理由
データベース設計を初めてするときにありがちなのが、
『Excelの表を作る感覚で、とりあえず全部1つのテーブルに入れる』
という設計です。
例えば、Excelで注文管理表を作るなら次のような形になるかもしれません。
+--------+----------+--------------------+----------+------+------+
| 注文ID | 顧客名 | メールアドレス | 商品1 | 商品2 | 商品3 |
+--------+----------+--------------------+----------+------+------+
| 1001 | 山田太郎 | yamada@example.com | パソコン | マウス | NULL |
+--------+----------+--------------------+----------+------+------+
Excelで数十件程度を管理するのであれば、これでも問題にならない場合があります。
しかしデータベースでは、注文ごとに購入する商品数が違うかもしれません。
商品を10個購入したら、
商品1
商品2
商品3
商品4
商品5
...
商品10
とカラムを増やすのでしょうか。
20個購入するユーザーが現れたら、さらにカラムを増やす必要があります。
この方法では、システムの仕様が変わるたびにテーブル構造まで変更しなければなりません。
通常は、
orders
と
order_items
のように分けて管理します。
orders
+----------+---------+
| order_id | user_id |
+----------+---------+
| 1001 | 1 |
+----------+---------+
order_items
+----------+------------+
| order_id | product_id |
+----------+------------+
| 1001 | 101 |
| 1001 | 205 |
+----------+------------+
これなら購入商品が2個でも100個でも、行を追加するだけで対応できます。
Excelは基本的に、
『人が表を見ながら管理する』
ことを中心に考えます。
一方でデータベースは、
『システムが大量のデータを検索・追加・更新する』
ことを前提に設計します。
そのため、Excelで見やすい表と、データベースとして扱いやすい構造は必ずしも同じではありません。
DB設計の大まかな流れ
データベース設計では、いきなりCREATE TABLEを書くわけではありません。
大まかには、次のような順番で考えていきます。
要件整理
↓
必要なデータの洗い出し
↓
テーブル設計
↓
リレーション設計
↓
制約の設計
↓
インデックス設計
↓
データベースへ実装
それぞれ簡単に見ていきます。
1. 要件を整理する
最初に、
『そのシステムで何をしたいのか』
を整理します。
例えばECサイトなら、
- ユーザーを登録する
- 商品を登録する
- 商品を購入する
- 注文履歴を見る
- 注文をキャンセルする
といった機能があります。
どのような機能が必要なのかによって、保存すべきデータも変わります。
そのため、DB設計はシステムの要件を理解するところから始まります。
2. 必要なデータを洗い出す
次に、システムで必要になるデータを整理します。
例えばECサイトなら、
ユーザー
商品
注文
注文明細
配送先
支払い
などが考えられます。
この段階では、まだ細かいテーブル構造を決める必要はありません。
まずは、
『システムで管理しなければならない情報は何か』
を洗い出します。
3. テーブルを設計する
必要なデータが見えてきたら、テーブルへ整理します。
例えば、
ユーザー → users
商品 → products
注文 → orders
注文明細 → order_items
といった形です。
さらに、
users
- id
- name
- email
- created_at
のように、各テーブルに必要なカラムを決めていきます。
4. テーブル同士の関係を設計する
テーブルを分けたら、今度はテーブル同士の関係を考えます。
例えば、
ユーザー
│
│ 1
│
└──── N
注文
│
│ 1
│
└──── N
注文明細
という関係があります。
1人のユーザーは複数の注文をすることができます。
また、1つの注文には複数の商品が含まれることがあります。
こうした、
『1対1』、『1対多』、『多対多』
などの関係を整理する作業をリレーション設計と呼びます。
5. 制約を設計する
次に、間違ったデータが登録されないようにルールを設定します。
例えばメールアドレスなら、
同じメールアドレスを複数ユーザーが使用できない
という仕様があるかもしれません。
その場合、
UNIQUE
制約を設定します。
ほかにも、
- PRIMARY KEY
- FOREIGN KEY
- NOT NULL
- UNIQUE
などの制約があります。
これらを適切に設定することで、データベース自身にデータの正しさを守らせることができます。
6. インデックスを設計する
データ量が増えると、検索速度も重要になります。
例えば100万件のユーザーから、
WHERE email = 'yamada@example.com'
で検索する場合を考えます。
適切なインデックスが設定されていないと、大量のデータを調べる必要があり、検索に時間がかかる場合があります。
そこで、
『どのカラムをよく検索するのか』
を考えながらインデックスを設計します。
ただし、インデックスは付ければ付けるほど良いわけではありません。
このあたりについては、後の回で詳しく扱います。
7. データベースへ実装する
設計ができたら、実際にデータベースへテーブルを作成します。
例えばMySQLやPostgreSQLなら、
CREATE TABLE users (
id BIGINT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE
);
のようなSQLを書いて実装します。
つまり、
設計
↓
SQL
↓
データベース
という流れです。
DB設計では、CREATE TABLEを書くこと自体よりも、
『なぜこのテーブル構造にするのか』
を考えることのほうが重要です。
DB設計で重要なのは「後から困らない構造」を考えること
データベース設計には、すべてのシステムに使える唯一の正解があるわけではありません。
同じようなシステムでも、
- データ量
- 更新頻度
- 検索方法
- 将来追加される機能
- システムの規模
- パフォーマンス要件
などによって適切な設計は変わります。
そのため、
『とりあえず動けばよい』
ではなく、
このデータはどこで管理するべきか?
同じ情報を重複して保存していないか?
データが増えても問題ないか?
仕様変更が起きても対応できるか?
と考えながら設計することが重要です。
もちろん、最初から完璧な設計を作ることは簡単ではありません。
DB設計ではさまざまな考え方やパターンを知り、実際に設計を経験しながら身につけていくことが重要になります。
このシリーズでは、そのために必要な知識を順番に解説していきます。
次回以降の予定
- 第2回:要件から「必要なデータ」を洗い出す
- 第3回:テーブル・カラム設計の基本
- 第4回:テーブル同士の関係を設計する
- 第5回:正規化を理解する
- 第6回:主キー・外部キー・UNIQUE制約を設計する
- 第7回:カラムのデータ型をどう決めるか
- 第8回:インデックス設計の基本
- 第9回:論理削除と物理削除
- 第10回:履歴データをどう設計するか
- 第11回:アンチパターンから学ぶDB設計
- 第12回:実際に1つのシステムをDB設計してみる