データベーステーブル設計の基礎の基礎~エンティティの抽出・定義から正規化まで

適切な形でデータベースのテーブルを設計し、運用するには?テーブル設計に必要な初歩を日本MySQLユーザ会副代表の坂井恵さんが丁寧に解説します。

データベーステーブル設計の基礎の基礎~エンティティの抽出・定義から正規化まで

金融系アプリ、ゲーム、人工知能などなど……。どんな種類のシステムを開発する上でも、避けて通れない領域があります。データベースです。データを適切な形式で格納し、取り出す。単純明快ながらも奥深いこの仕組みは、多くのシステムの根幹を支えています。

しかし、適切な形でデータベースのテーブルを設計し、運用するのは簡単なことではありません。「良いテーブル設計」のためには知識と経験が不可欠です。今回は日本MySQLユーザ会の副代表である坂井恵さんに、これからテーブル設計に着手する方に向け、設計に必要な技術と、良い設計を作るための考え方を教えていただきました。

坂井恵(さかい・けい) 1@sakaik
日本MySQLユーザ会副代表。データベースを中心とした社内システム設計・コンサルティングを手掛ける有限会社アートライの代表を務める他、SQL関連書籍の執筆も多数。著書に『MySQL徹底入門(共著 刊:翔泳社)』など。

フェーズ1:エンティティの抽出

2

エンティティ(実体)とは、ある共通項を持ったデータの集合体のこと。テーブル設計においては、なによりもまず、「エンティティをいかに設計するか」が重要です。このフェーズでは「システムに必要なエンティティ(=データ)は何か?」を洗い出していきます。
物理的なエンティティの例:社員、店舗、商品など
概念的なエンティティの例:購入履歴、進捗状況など

最初は大きいものから抽出していく

──エンティティを抽出する際、坂井さんはまず何から着手しますか?

坂井 このフェーズにおいては「なるべく大きな要素から抽出していく」のが大切です。仮に「車をWeb上で販売するサービス」のデータベースを設計するならば、私なら「車」と「顧客」という粒度の大きなエンティティから考えていくでしょう。

3

──「メーカーは何か?」「顧客の年齢や居住地は?」など、つい細部が気になってしまう方もいると思います。このフェーズでそうした情報を検討する必要はないのですか?

坂井 そうしたアイデアが途中で浮かぶこともあると思います。でも、エンティティ抽出の段階で細部から考えてしまうと、情報の粒度がそろわなくなってしまいますし、不要なエンティティを無駄に検討してしまう可能性も高いです。

とはいえ、途中で浮かんだ「こんな情報が必要かもしれない」というアイデア自体は価値が高いので、それらは別途メモしておき、後続のフェーズで利用すればいいと思います。

4

エンティティ抽出と要件定義は表裏一体である

──大きな単位でエンティティを抽出したら、次は何をすべきですか?

坂井 「エンティティ同士でどんな出来事・状態変化が起きるか?」を考えていくといいですね。

車をWeb上で販売するサービスの場合、「お客さんが車を注文する」という出来事は絶対に起こりますし、取引の記録を残しておかなければマズいですよね。その出来事そのものが、1つの概念的なエンティティになります。

5

つまり、システムの登場人物(物理的エンティティ)を大きな塊として洗い出した後、それらがシステム内でどう使われるのか、どんな情報を残す必要があるのかを考えていきます。エンティティ抽出のプロセスは、ほぼ要件定義そのものなんです。

──とはいえ、それらの要件を洗い出すのは、慣れていないと大変な作業に思えます……。

坂井 これらを考えるコツがあります。「システムがどう使われるのか、脳内で入念にシミュレーションすること」「要件の不明点を丁寧に潰していくこと」です。

システムの各種ユースケースをシミュレーションしていくと、「こんな事態が発生した場合、こういうデータが必要だ」とか「この情報は不要ではないか」などが分かってきます。

例えば、購入プロセスのなかで「仮注文」「本注文」「入金完了」といった状態変化があるならば、「その状態を何らかの方法で残さなければいけない」ということが見えてきます。必然的に、必要なエンティティも理解できるわけです。

また、シミュレーションのなかで要件の不明点が出てくるので、要件を決定する人にヒアリングをし、それらの点を一つ一つクリアにしていきます。

フェーズ2:エンティティの定義

6

各エンティティがどのようなデータ(カラム)を保持すべきかを定義するフェーズ。リレーショナルデータベースにおいてエンティティはテーブルで表現されるため、エンティティの定義とはテーブル定義とほぼ同義といえます。

必要なカラムは「起こり得るユースケース」「最終的にアウトプットすべき内容」をベースに導き出す

坂井 エンティティ抽出後、エンティティにどんなカラムが必要かを洗い出していきます。車ならば、メーカーや車種、色、年式などです。先ほど話したような、注文状況などの情報も持たせる必要があるかもしれません。

──洗い出しの漏れを少なくするには、どうすればいいですか?

坂井 くり返しになってしまいますが、さまざまなユースケースをシミュレーションすることが、このフェーズでも重要になります。

「もし注文がキャンセルされたら」「もしお金が支払われなかったら」など、多種多様なパターンを考えてみてください。そうすることで、それらの状態を管理するためにどんなカラムが必要かが見えてきます。

また、「画面・帳票にどんな内容が表示されるか?」を考えるのも良い方法です。表示される項目はデータベースに由来することが多いので、エンティティを定義する上で大きなヒントになります。

「注文がキャンセルされた」というユースケースをもとに、必要なエンティティを検討する場合、以下のように状態変化に応じて、データベースがどのような情報を保持すべきかを考えることで、必要なエンティティが見えてくる。

注文がキャンセルになる

「注文がキャンセルになった」という状態と、
顧客への返金先などを保持しておく必要がある

注文の状態を持つエンティティが必要ではないか?
顧客のエンティティに口座番号を持っておくべきでは?

具体的なテーブルやカラムに落とし込む

カラム名のシノニム・ホモニムには気を付ける

──「エンティティの定義」のフェーズでは、テーブルのカラム名も悩ましいポイントです。命名する上で大事なことはありますか?

坂井 カラム名のシノニム(呼び名が異なっているが、同じ意味を持つ語)・ホモニム(呼び名が同じだが、異なる意味を持つ語)には注意してほしいです。

シノニムとしてよくあるのは、

  • 顧客情報を持つ「customer」テーブルの顧客名を持つカラムを「customer_name」という名前にする
  • 「customer」テーブルとの関連付けのため、別のテーブルに「kokyaku_name」という名のカラムを持たせる

といった例です。これを避けなければいけません。なぜなら、「『customer』テーブルにある『customer_name』と別テーブルにある『kokyaku_name』は同じものだ」という前提知識を、エンジニアが知る必要が出てくるからです。

この場合は、両テーブルのカラム名を「customer_name」に統一しましょう。

7

同様に避けるべきケースとして、カラム名のホモニムがあります。例えば、ある店舗のデータベースのなかに「取引先企業の情報を持つテーブル」と「一般顧客の情報を持つテーブル」があるとします。

両テーブルの「顧客(取引先 or 一般客)名」のカラム名を「customer_name」にしてしまう、というのが一番マズいケースです。同名にもかかわらず意味が異なるため、エンジニアが混乱してしまいます。

8

「同じ情報を持つカラムは同じ名前にする」「異なる情報を持つカラムは異なる名前にする」のがネーミングの原則です。

日本語ローマ字表記のテーブル名・カラム名は悪か?

ネーミングに関して「日本語ローマ字表記のテーブル名・カラム名をつけてはいけない」と言われることがあるが、必ずしもそうではないと坂井氏は語る。なぜなら、テーブル名・カラム名において何より重視すべきは「開発メンバーの大多数が意味を理解できることだから」とその背景を説明する。

例えば、英語の辞書を参照しながら見慣れない英単語をテーブル名やカラム名につけた場合、エンジニアが十分に理解できないまま作業することになり生産性は落ちてしまう。それよりも、誰もが理解できる日本語ローマ字表記を使った方が生産性が高くなるというわけだ。

逆に、チームに外国人が多いなど、日本語が理解できないメンバーもテーブルを利用するならばむしろ英語名で統一すべきだと付け加える。いずれにしても重要視すべきは「どんな人がその名前を読むのかを考慮すること」だと坂井氏は強調する。

フェーズ3:正規化

エンジニアHubに会員登録すると
続きをお読みいただけます(無料)。
登録のメリット
  • すべての過去記事を読める
  • 過去のウェビナー動画を
    視聴できる
  • 企業やエージェントから
    スカウトが届く