1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

データベース設計、後から後悔しないために

Last updated at Posted at 2025-09-04

はじめに

昨日、社内ミーティングで改めて感じたこと、そしてXでもよく見かける意見に深く共感した話です。一度決めたデータ構造は、想像以上に後から変更が難しいものです。

データ構造は一度決めたら変えにくい

アジャイル開発では、ソースコードはリリース後もリファクタリングやリプレイスが可能です。しかし、データベースのテーブル定義だけは、一度データが蓄積されてしまうと、後からの変更が非常に困難になります。

技術的にはALTER TABLEで変更できますが、デッドロックの発生、既存データへの影響、データ整合性の確保など、事故のリスクが大きく、運用コストも高いため、極力避けたいのが実情です。

DB変更時に特に気をつけたいこと

スペルミスは絶対に避ける

これは絶対にNGです。後から見ると格好悪いだけでなく、影響範囲が広大です。開発のたびに過去の過ちを掘り返されるような感覚に陥ります。
AIによるスペルチェックなどを積極的に活用し、複数人でのレビューも行いましょう。

NG例(間違いがわかりますか?)

catagory  → category
usrname   → username
Refrence  → Reference

命名規則とデータ型の統一

可能な限り一般的な基本ルールに忠実に揃えましょう。組織内に既存の命名規則がある場合は、それに統一するのが良いでしょう。特に日付系のカラムは、テーブルを跨いで統一されていると理解しやすいです。

推奨例:

作成日:created_at(datetime型)
更新日:updated_at(datetime型)

どのデータを格納するか(値の持たせ方)

statusカラムのように、Rubyのenumを使う場合は、DBには直接「エラー」「処理済み」といった文字列ではなく、数字を格納することが推奨されます。

また、別テーブルの変更内容を記録するようなケースでは、以下のように全く同じカラム構造を複製するのではなく、柔軟なデータ構造を検討するのも良いアイデアです。

従来の方式:

create_table "target_table" do |t|
  t.string "fizz_column", limit: 1, default: "0", null: false, comment: "カラム1"
  t.string "buzz_column", limit: 1, default: "0", null: false, comment: "カラム2"
end

create_table "other_table" do |t|
  t.string "fizz_column", limit: 1, default: "0", null: false, comment: "カラム1"
  t.string "buzz_column", limit: 1, default: "0", null: false, comment: "カラム2"
end

拡張性を考慮した方式:

create_table "other_table" do |t|
  t.json "columns_hash", null: false, comment: "カラム情報をハッシュ形式で保持"
end

このようにハッシュで保存することで、target_tableのカラム変更やother_tableへのカラム追加が必要になった際も、プログラムの修正だけで対応できるようになります。

可能な限りDB変更をしない開発を意識する

ぶっちゃけ、SQLの実行自体は極力減らしたいものです。ridgepoleのようなツールがあるとはいえ、リリース時にDB変更を意識しなくて済むよう、拡張性のあるテーブル構造を心がけましょう。

物理削除と論理削除の適切な選択

delete_flagが必要なのか、本当に熟考すべき点です。顧客情報など、履歴保持が必須なデータ以外は、どちらが適切か十分に検討しましょう。

個人的には、論理削除(delete_flagdeleted_atを使う)の場合、生きているデータを取得する際にSQLで毎回WHERE delete_flag = false(またはWHERE deleted_at IS NULL)といった条件が必要になり、スコープの設定忘れなどによる不具合のリスクも考慮すると、できれば物理削除が望ましいと考えています。

一見でわかるDBやカラム名

ソースコードや仕様書を見なくても、何のためのテーブルなのか、雰囲気で掴めるような名前が理想です。機能名をそのまま英訳するのではなく、なるべく一般的な命名規則や慣例に置き換えられないか、常に考える習慣をつけましょう。

created_atupdated_atに作成日と更新日以上の役割を持たせない

例えば、ユーザーの会員登録日にcreated_atを使ったり、ユーザーの退会日にupdated_atを使うべきではなく、それぞれ専用のカラムを持たせてそこに値を格納し、参照するのが良いと思っています。
updated_atは特に、何かあってデータが書き換わると簡単に変わってしまうため、あまり当てになりません。

まとめ

データ構造は、一度決めたら長く残り、その後の開発に大きな影響を与えます。安易な決め方をすると、技術的負債として将来のエンジニアにのしかかります。妥協せず、じっくり考えてチーム内で議論を尽くし、納得のいく形で決定することが、何よりも大切だと改めて感じました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?