DBのテーブル構造のアンチパターンと改善

みなさんこんにちは。 エキサイトでエンジニアをしているAです。

エキサイト内で過去に一部テーブル構造の見直しを行い、運用コストの効率化を行ったため今回はその一例をご紹介いたします。

最初にテーブル構造からしっかり考える

最初のテーブル構造は非常に大事です。今回は以下の3点を特に重視していきました。

  • テーブル構成は要件に合わせて基本的に細かく分ける
  • 後々拡張しやすい造りにする
  • テーブルを見るだけでなんのデータか把握しやすい形にする

上記は当たり前のことですが、ここを疎かにしてしまうと後々何の為に使うデータか分からなくなったり、データが増えてしまいデータの更新処理に時間がかかったりします。

後付けで謎テーブルを謎ロジックでJOINしたりで、とんでもなく複雑な運用になってしまいがちです。

テーブル定義は時間をかけて行っていったかどうかで運用の手間が全然変わります。

見切り発車で決めるのだけは絶対にやめましょう。

テーブル例

`example_table` (
id,
name,
profile_json,
snsA_profile_json,
snsB_profile_json,
url_information_json,
TypeA_json,
TypeB_json,
TypeC_json,
...
...
...
active_flag,
delete_flag)

実際に存在していたテーブルの一例です。 この場合、カラムが非常に長いため一つのテーブルに大量のカラムを作成せず、分けられる箇所は分けるようにしていきます。

問題点1 データの更新に無駄に手間がかかる

恐ろしい事にこのケースだとデータをSQLに投げる際に、jsonをカラムにそのまま突っ込んでいます。

そのため、既に登録したデータの中身の情報を変えたい時にデータを投げ直す事になり迂闊にデータを変えることができなくなります。

例えばID1のTypeAの情報を一部変更したいなどの要件があった場合、以下の操作をするしか変える手段はありません。

  • jsonの中身を把握してUPDATEをかける
  • データを再度入れ直して上書きする

この場合TypeAの情報を一部分変えるだけでも苦労します。これだけでもう地獄です。

解決策

今回はTypeAはTypeA_json用のデータをまとめたTypeAテーブルなど分けるように変更を加えました。

その後DBから受け取るAPI側でjsonに変換して送るようにする事で、TypeAJsonカラムに影響されることはなく TypeAの情報は単純なUPDATE文一つで更新できるようになりました。

問題点2 状態をカラムを持っている

今回のテーブルにはactive_flagというものが存在します。 active_flagとみたら誰もが「表示、非表示の状態を持つカラムなんだな」と思うかもしれません。

実際にこのテーブルのコメントには「アクティブフラグ」とだけ書いてありました。

パッと見0や1が書いてあるので1が表示で0が非表示なんだなーとなんとなくわかりそうです。

しばらくデータを眺めていると1や0の中に-1や-128という知らない数字が見えました。

どうやらこの表示フラグ、表示のためのフラグなのに4つのカオスな状態を持っているようです。 実際に使われていた箇所を追っていくと、

  • データが入ってきたばかりの状態 => 0
  • 管理画面で公開許可された状態 => 1
  • 管理画面で非許可にされた状態 => -1
  • 削除予定の状態 => -128

と言った形で使われていることがわかりました。

実装当時の状況はわかりませんが、恐らくはじめは1,0で表示管理されていた物が表示要件が新たに出てきたので付け足されていったのだと推測しました。

解決策

結局のところ0,1,-1,-128が要らないので、いっそ分けた方がやりやすいです。

active_flag自体はカーディナリティが低いので、example_tableのactive_flagで状態管理するのをやめました。

activeな状態のIDを下記のようにactiveテーブルに入れることで分かり辛さが解決します。

`example_active` (
id
)

activeにactiveな情報を持つIDだけ入れておけば、テーブルを見るだけでどれが今activeなのかは自明です。

さらに後から追加要件で変な状態を持たせられることもなくなります。

ちなみにアクティブかどうかと、非許可かどうか、削除するかどうかは要件がそもそも別なのでテーブルを分けるべきです。

どうしても値で状態を持たなければならなくなった場合は、当たり前の話ではありますがせめてどの値がどれを示すかのコメントはしっかり残しましょう。

その他、紹介し切れていない改善点などはまだまだありますが ご覧の方々には、最初のテーブル定義にはしっかり時間をかけるという認識を持っていただけたら、後々の運用もやりやすくなる筈なのでこれを機にテーブル構造には時間をかけて考えていただく切っ掛けになれば幸いです。