こんにちは。東京技術チームの馮です。
先日の社内勉強会でWJSチームの高崎さんより「SQLアンチパターン」を開催してくれましたので、その内容を共有したいと思います。
0. 背景
普段は、リレーショナルデータベースを中心に据えたシステム開発には、様々な場面で陥りやすい失敗(アンチパターン)があります。今度の共有は、実務経験より数例を挙げ、なんでアンチパターンなのか、どうやって避けるのはについて説明いただきました。
1. ジェイウォーク(信号無視):カンマ区切りフォーマットのリストを格納していないか?
💡 下記の通り、product_idをPriamary Keyにして、name, category, height, weightという属性を持っている「products」テーブルがあります。
どこかから現れる新規要望
日本酒は、酒カテゴリだけじゃなくて食品カテゴリとしても検索出来るようにしたいなあ🤔🍶
対応するように、
- Categoryに複数の値を持つ、属性を格納したい。。。
- でも出来るだけ、DBへの変更は最小限にしたい。。。
- Categoryはvarcharなので、文字列として区切りを入れれば出来るかも?
なぜこれがアンチパターンなのか?
- カンマ区切りの場合、
- like演算子などでパターンマッチさせる必要があるが、その場合、正しい検索結果が得られない可能性がある。
- (食品、健康食品など)また設定したindexが使えない場合がある。
- カンマ区切りのカラムに対してJOINがしにくい
- 集計が難しい
- 区切り文字(今回の場合カンマ)そのものが入力されない保証がない etc…
対応策
- 交差テーブルを作成する
2. なんでもかんでも無邪気に主キーとして id
を定義してしまう
💡 すべてのテーブルにID列を用いる
そもそもなぜIDが必要なのか?
- テーブルの主キー(Primary key)を持つため
- すべての行が1意(unique)であることを保証するため
- つまり、他の方法で保証出来ればIDは不要でもOK
なぜこれがアンチパターンなのか?
- 冗長なキーが作成されてしまう
- 行の重複を許可してしまう
- キーの意味がわかりにくくなる
対応策
- IDだけでなく分かりやすい列名にする。例えば、「products」テーブルのidを「product_id」にすることによって、テーブル名を見なくても、 何のIDか判断出来る方が良い
3. 31のフレーバー
💡 限定する値を列定義で指定する
なぜこれがアンチパターンなのか?
- 新しいフレーバーの追加が難しい
- ALTER TABLEで列定義は変更可能だが、そのためには「現在の有効値」を調査する必要がある。
- アプリケーションコード側との差異も出やすい。
- そもそもALTER TABLE(テーブルの再構築)のコストは高く頻繁に実行すべきではない。
- 古いフレーバーの削除が難しい
- 既存のカラムに、削除対象があればデータメンテが必要になる。
対応策
- 限定する値をデータで指定する
- 効果としては、
- 値セットの取得が簡単
- 参照テーブルの値の更新が簡単
- 廃止された値のサポートがしやすい
所感
今回、アンチパターンという言葉は初めて聞いたが、やはり気をつけないと陥りやすいことを感じました。今後、テーブル設計時、「拡張性」や「高速性」等に基づいて、アンチパターンであるかを判断することをチェックリストに入れておきましょう。