teacher asking a question to the class
Photo by Max Fischer on Pexels.com

【授業レポート】システム開発(2年) 第35週目 〜データベース設計(ER図)と永続化の落とし込み〜

第35週目は、先週作成したクラス図を元にデータベース(永続化)設計へ落とし込む実習を行いました。クラスの属性をどのようなテーブルにし、どのように関係(リレーション)を張るかを考えることで、実際に動くシステムの骨格を作る重要な回です。


■ 先生の導入:「メモリの中の“箱”をディスクに保存する設計」

田中先生:「クラスで定義したデータは、実際にはテーブルとレコードになります。UMLの属性をそのままテーブルに落とすだけでなく、正規化・インデックス・トランザクションなど運用を意識して設計することが大事です。」


■ 今日のポイント(要点)

  • ER図でエンティティ(テーブル)と関係を定義する。
  • 正規化(1NF〜3NF)を意識して冗長性を減らす。
  • 主キー/外部キーの設定と参照整合性(FK制約)。
  • インデックス設計(検索頻度に応じた適所のインデックス)。
  • 簡単なマイグレーション(CREATE TABLE / ALTER)とサンプルデータで挙動確認。
  • トランザクション・バックアップ・セキュリティ(SQLインジェクション対策)まで運用視点で検討。

■ 実習①:UML → ER図 に落とすワーク

班ごとに、クラス図の属性をどのテーブルに配置するかを議論。ポイントは次の通り。

  • エンティティ化の判断:クラスが独立したライフサイクルや複数参照されるなら別テーブル(例:Book, Member, Loan)。
  • 多対多の扱い:多対多(Member と Book の貸出)は中間テーブル(Loan)で表現する。
  • 属性の正規化:住所や複数電話番号は別テーブルに分割するか検討する(繰り返し属性の排除)。

例:図書館システムの簡易ER(要旨)

  • members(id PK, name, member_id, created_at)
  • books(id PK, title, author, is_reference, is_available)
  • loans(id PK, member_id FK→members.id, book_id FK→books.id, borrowed_at, due_date, returned_at)

生徒の気づき:「Loan を作ると、貸出履歴や延滞チェックが自然に扱える!」


■ 実習②:正規化の確認(1NF→3NFのチェック)

班ごとにテーブル設計が正規化されているかを確認。

  • 1NF:列は原子値で、繰り返しカラムを持たない(例:phone1, phone2は避ける)。
  • 2NF:部分関数従属を排除(複合PKを使う場合の注意)。
  • 3NF:非キー属性はキーに対してのみ依存すること(派生データは別テーブル/ビューへ)。

例:もし bookslibrary_branch_name を入れているなら、branches テーブルに分ける方が適切、という指摘が出ました。


■ 実習③:SQLで作って動かしてみる(マイグレーションとサンプル)

授業では簡単な SQL を書き、学習用DBに適用して動作確認を行いました(SQLite / PostgreSQL の学習環境想定)。授業で使った例:

-- members テーブル
CREATE TABLE members (
  id SERIAL PRIMARY KEY,
  member_id VARCHAR(20) UNIQUE NOT NULL,
  name VARCHAR(100) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- books テーブル
CREATE TABLE books (
  id SERIAL PRIMARY KEY,
  title VARCHAR(200) NOT NULL,
  author VARCHAR(100),
  is_reference BOOLEAN DEFAULT FALSE,
  is_available BOOLEAN DEFAULT TRUE
);

-- loans テーブル(中間テーブル)
CREATE TABLE loans (
  id SERIAL PRIMARY KEY,
  member_id INTEGER NOT NULL REFERENCES members(id),
  book_id INTEGER NOT NULL REFERENCES books(id),
  borrowed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  due_date DATE,
  returned_at TIMESTAMP NULL
);

その後、サンプルデータを挿入して JOIN クエリで動作確認。

INSERT INTO members (member_id, name) VALUES ('M001', '田中');
INSERT INTO books (title, author) VALUES ('ハリーポッター', 'J.K.ローリング');

-- 貸出処理(トランザクションで)
BEGIN;
INSERT INTO loans (member_id, book_id, due_date) VALUES (1, 1, '2025-12-01');
UPDATE books SET is_available = FALSE WHERE id = 1;
COMMIT;

-- 貸出中の本を取得
SELECT b.title, m.name, l.borrowed_at, l.due_date
FROM loans l
JOIN books b ON l.book_id = b.id
JOIN members m ON l.member_id = m.id
WHERE l.returned_at IS NULL;

生徒の反応:「トランザクションで貸出と在庫更新を一緒にやると、途中で失敗しても整合性が保たれる!」


■ 実習④:インデックスとパフォーマンスの基礎

テーブルを作ってデータ量が増えた場合の検索を想定し、どのカラムにインデックスを張るかを議論。

  • 検索頻度の高い books.titlemembers.member_id にインデックスを検討。
  • JOIN に使う loans.book_id / loans.member_id はインデックス効果が高い。
  • 一方、更新頻度が高いカラムや低選択性カラム(真偽値)には不要なインデックスは避ける。

簡単なSQL例:

CREATE INDEX idx_books_title ON books(title);
CREATE INDEX idx_loans_member_id ON loans(member_id);

生徒の気づき:「インデックスは速くするけど、書き込みが遅くなるトレードオフがあるんだ」


■ 実習⑤:運用面の考慮(バックアップ・マイグレーション・セキュリティ)

  • バックアップ:定期ダンプ(pg_dump 等)やポイントインタイムリカバリの概念。
  • マイグレーション:スキーマ変更は段階的に(ALTER の注意、ロールバック案の準備)。
  • セキュリティ:プレースホルダ付きクエリで SQL インジェクションを防ぐ(例:cursor.execute("SELECT ... WHERE id=%s", (id,)))。
  • 権限管理:DBユーザーは最小権限の原則(読み取り専用ユーザーなど)。

田中先生:「設計が良くても、運用でデータを失ったり漏洩したりしたら意味がありません。永続化は“最後の責任”でもあります。」


■ 先生のひとこと

「データ設計は、アプリの信頼性と性能を大きく左右します。クラス図からER図へ、ER図からDDLへ、そして運用へ――この流れを意識して設計すると、実装もテストもスムーズになります。次週はER図を確定し、実際のマイグレーションスクリプトを班で作成します。」


■ 宿題(次回に向けて)

  1. 班の**最終ER図(PNG/PDF)**と、今回作成した CREATE TABLE(DDL)スクリプト を提出。
  2. 各テーブルについて 想定インデックス案 を3箇所以上書き、その理由を各20〜60字で説明。
  3. 「データ損失が起きたときのロールバック手順」を1ページ以内で作成(バックアップ→復元の流れ)。

第35週目は、設計を永続化のレベルまで落とし込み、実践的なSQLと運用の知見を得る週でした。生徒たちは「設計=約束」「DBは慎重に扱うべき資産」という認識を深め、次の実装フェーズに向けて準備を整えました。

投稿者 greeden

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)