文字列のリストを単一のデータベースフィールドに格納することは悪い考えですか?どうして?


14

最近、いくつかのレガシーシステムに取り組み始めました。それを開発した人々は、データベーステーブルの単一のフィールドに文字列のリストを格納するというアイデアを思いつきました。これは、データベースに表現もデータもないオブジェクトの識別子であるとしましょう。その識別子の範囲は、本番環境では比較的小さくなります。

一方、私の直感と「良いデザインの好み」は、別のテーブルで表現する必要があることを示しています(多対多の関係を表すために使用されるテーブルと同様)。

彼らのアプローチは本当に悪いのですか?リファクタリングを開始する方が良いでしょうか?はいの場合、元の設計が将来どのような悪影響をもたらす可能性がありますか?そのアプローチを説明するリレーショナルデザインの原則はありますか?

コメントの返信を編集:

おそらく、彼らはこのアプローチを使用して、階層構造化などの特定の問題を巧妙な方法で解決していません。最もありそうなシナリオは、彼らが時間のプレッシャーの下で単に働いていて、できるだけ早く新機能を実装する必要がある場合でした。

以前はフィールドが単一の値を表していたと思います。彼らは複数の値を保存する機能を実装する予定で、データベースの移行を回避しようとしました。


6
それが悪いアプローチであるかどうかは、それが解決しようとしていた問題と、それがどれだけうまく解決したかによって異なります。それについてより具体的な情報を提供できますか?
Robert Harvey、

1
リストに対してクエリを実行するか、リストからレポートを作成する場合にのみ問題になります。これらが要件である場合、おそらくよりリレーショナルなアプローチが必要になります。永続化だけの場合は、大きな問題になるはずです。
Jon Raynor

2
それが「正しい」ことであるとしても、コレクションアイテムの高速インデックス作成の必要性など、この戦略では対応できない何かを必要とする新しい要件が得られるまで、リファクタリングを開始しません。
Graham

このような列の更新も問題になる可能性があります。

1
@graham新しい要件は次のとおりです。「これで動作するクエリが必要です」。この上に構築し、すぐにそれを殺さないことで、あなたは実際に取り除くことと正しいことをすることを難しくします。問題は、この戦略を使用してもほとんどのことができるということです。SELECT * FROM Products AS p JOIN Accounts AS a ON p.account_id REGEXP '[[:<:]]' || a.account_id || '[[:>:]]' WHERE p.product_id = 123;
Pieter B

回答:


16

データモデルは正規化されていません。そうするためには、別のテーブルが必要になります。その点で、それは特に優れたデータモデリング手法ではありません。

それが正当な理由で行われたかどうかを判断することは困難です。おそらく、コーディングの簡素化またはパフォーマンスが動機であった可能性があります。おそらく、フィールドには元々1つの識別子が含まれていたため、要件が変更され、開発者はリファクタリングする時間や傾向がありませんでした。

おそらくもっと重要なのは、リファクタリングする必要があるかどうかです。同様の状況では、デフォルトでこのようなケースを事前にリファクタリングしません。次のいずれかが当てはまる場合、私はそれを検討します。

  1. これが問題を引き起こすという証拠があります。たとえば、レガシーの問題ログから
  2. あなたはその領域で機能的な変更を行うことを知っています
  3. データを処理するコードは特に複雑で、推論が困難です。

私がやろうとしていること、そしてTBHは、レガシーアプリケーションを引き継ぐときはいつでも、このようなwiki(または同等のもの)を開始してドキュメントを作成することをお勧めします。例えば、

  • データモデリングのしわなど、見つけた問題
  • 実装する予定の変更
  • 実装する予定はありませんが、時間があれば変更します
  • 推論するのが難しいコードの領域
  • 維持するのが難しいコード領域。

これは、コードベースで作業したり、コードベースに戻ったりするときに役立つ助手メモであることがわかりました。また、後継者がコードベースの学習を開始する必要があるときに、後継者にとって非常に役立ちます。


10

文字列のリストを単一のデータベースフィールドに格納することは悪い考えですか?

これは通常、正規化違反と見なされます。

ただし、これは、たとえば、ある種の可変長パス文字列が構造を表す階層構造などの問題の解決に使用される場合があります。

単一の文字列内のアイテムのリストに関する問題には、次のものがあります。

  • クエリでは、これはリレーショナル計算の代わりに文字列検索を使用することを意味します。データのインデックス作成には問題がある場合があります。
  • リスト内のエントリの順序付けの意味についての質問があり、DBの制約として順序付けに何も強制できないことがほとんどです。
  • 区切り文字の問題と、個々のアイテムでの文字のエスケープ/エスケープ解除の問題の可能性があります。
  • 同じリスト内のエントリが重複する可能性があります。繰り返しになりますが、これは制約を直接適用できないことに起因します(ただし、トリガー関数は制約をチェックできます)。
  • 単一のアイテムだけでもリストですが、データベースに真のタイプがリストであることを伝える(または尋ねる)ことができないため、そうではない可能性があります。ほとんどの行がリストに1つだけの項目を持っている場合、一部の行に複数の項目がある場合、これは問題になる可能性があります。列をリストとして適切に使用することを強制する方法はありません。

私は両方の答えに感謝しますが、アレックスを選択したのは、自分で最良の決定プロセスを行う方法について貴重なヒントが得られたからです。
mpasko256 2017年

3

これを行うのが一般的なアンチパターンです。

要件が変化し、かつては1つしか必要でなかった場所に、より多くの値が必要になりました。本のように、著者は1人だけですよね?本に複数の著者がいると誰が推測したでしょうか?これは、データベーススキーマを変更せずに、この要件の変更を満たす簡単な方法です。

しかし、いくつかの欠点もあります。

  • 1つのフィールドに結合された識別データがあるため、クエリはより困難になります。
  • "="は使用できなくなりましたが、 "like"などを使用する必要があります。パフォーマンスが低下します。
  • そのフィールドに参加する能力を失います。
  • カウント/合計などを試してください、それは動作しません。
  • 更新すると、ぎこちなくなります。
  • コンマ区切りリストを保持するためにvarchar(10)を選択したため、人工的な制限のようになっています。
  • もっと。

したがって、基本的には、これを行わないでください。

基本的には、「リレーショナルデータベース」の「リレーショナル」を取り出します。


0

私たちが悪い考えであるという議論はすでにたくさんあります。それが良い、または少なくともOKなアイデアである理由をいくつか追加するのは公平だと思います。これらのうちいくつが特定のケースに当てはまるかはわかりませんが、少なくとも実行されたパフォーマンスの注釈が関連しているようです。

  • 文字列の数と長さが厳密に制限されている場合は、パフォーマンスの違いはごくわずかです。少なくとも一部のエッジケースでは、結合が必要ないため、パフォーマンスが向上します。
  • フィールドの主な用途によっては、このフォームの方が扱いやすい場合があります。
  • リストが順序付けられていて、データに外部キーが必要ない場合、リストフィールドは、この点に関してリレーショナルデータベースが提供できるものよりもはるかに優れています。
  • 既存の特異なフィールドに単純に便乗することは、スキーマの移行にコストがかかるシステムでは賢明な選択かもしれません。それは確かに技術的な負債ですが、時々関心を払う必要がある場合でも、取る価値があり、決して返済しない価値がある種類かもしれません。

リファクタリングを試みる場合、常に以前の設計選択の背後にある理由を最初に理解することは常に良い考えです。条件と要件が実際にコストとリスクを正当化するのに十分に変更されていることを確認してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.