400

チェックボックスのセットを備えたWebフォームを想像してみてください(それらのいずれかまたはすべてを選択できます)。データベーステーブルの1つの列に格納されている値のコンマ区切りリストにそれらを保存することを選択しました。

これで、正しい解決策は2番目のテーブルを作成し、データベースを適切に正規化することであることがわかりました。簡単なソリューションを実装する方が迅速でした。そのアプリケーションの概念実証を、あまり時間をかけずにすばやく実行したかったのです。

私の状況では、節約された時間と単純なコードはそれだけの価値があると思いました。これは防御可能な設計上の選択ですか、それとも最初から正規化する必要がありますか?

もう少しコンテキストとして、これは、共有フォルダーに保存されていたExcelファイルを本質的に置き換える小さな内部アプリケーションです。プログラムをクリーンアップして、より保守しやすくすることを考えているので、私も質問しています。そこには私が完全に満足していないことがいくつかありますが、そのうちの1つがこの質問のトピックです。

4

10 に答える 10

626

単一の列に格納された値のグループが繰り返されるために第一正規形に違反することに加えて、コンマ区切りのリストには他にも多くのより実用的な問題があります。

  • 各値が正しいデータ型であることを確認できません:1,2,3、banana、5を防ぐ方法はありません
  • 外部キー制約を使用して値をルックアップテーブルにリンクすることはできません。参照整合性を強制する方法はありません。
  • 一意性を強制することはできません:1,2,3,3,3,5を防ぐ方法はありません
  • リスト全体をフェッチせずにリストから値を削除することはできません。
  • 文字列列に収まる長さより長くリストを格納することはできません。
  • リスト内の特定の値を持つすべてのエンティティを検索するのは困難です。非効率的なテーブルスキャンを使用する必要があります。
    idlist REGEXP '[[:<:]]2[[:>:]]'たとえば、MySQL:またはMySQL 8.0:では、正規表現に頼らなければならない場合があります。idlist REGEXP '\\b2\\b'
  • リスト内の要素を数えたり、他の集計クエリを実行したりするのは困難です。
  • 値を参照するルックアップテーブルに結合するのは困難です。
  • ソートされた順序でリストをフェッチするのは難しい。
  • 値に表示されないことが保証されているセパレータを選択するのは難しい

これらの問題を解決するには、RDBMSがすでにはるかに効率的に提供している機能を再発明して、大量のアプリケーションコードを作成する必要があります。

コンマ区切りのリストは十分に間違っているため、これを私の本の最初の章にしました:SQLアンチパターン:データベースプログラミングの落とし穴の回避

非正規化を採用する必要がある場合もありますが、@ OMG Poniesが言及しているように、これらは例外的なケースです。非リレーショナルの「最適化」は、データの他の使用を犠牲にして1つのタイプのクエリに利益をもたらすため、非正規化に値するほど特別に処理する必要があるクエリを知っていることを確認してください。

于 2010-09-06T18:26:54.353 に答える
48

「1つの理由は怠惰でした」。

これは警報ベルを鳴らします。このようなことをすべき唯一の理由は、それを「正しい方法」で行う方法を知っているということですが、そのようにしないという具体的な理由があるという結論に達しました。

そうは言っても、この方法で保存することを選択したデータが、クエリを実行する必要のないデータである場合は、選択した方法で保存する場合があります。

(一部のユーザーは、「将来どの要件が追加されるかわからない」と言って、私の前の段落のステートメントに異議を唱えます。これらのユーザーは、誤った方向に進んでいるか、宗教的な信念を述べています。あなたの前に持っています。)

于 2010-09-06T18:22:12.040 に答える
42

SOの質問には多くの質問があります。

  • カンマ区切りのリストから特定の値のカウントを取得する方法
  • カンマ区切りのリストから同じ2/3/etc固有の値のみを持つレコードを取得する方法

カンマ区切りリストのもう1つの問題は、値の一貫性を確保することです。テキストを保存すると、タイプミスが発生する可能性があります。

これらはすべて非正規化データの症状であり、常に正規化データをモデル化する必要がある理由を浮き彫りにします。非正規化クエリの最適化であり、ニーズが実際に発生したときに適用されます

于 2010-09-06T18:17:38.197 に答える
19

一般に、プロジェクトの要件を満たしていれば、何でも防御できます。これは、人々があなたの決定に同意したり、擁護したりするという意味ではありません...

一般に、この方法でデータを保存することは最適ではなく(たとえば、効率的なクエリを実行するのが難しい)、フォームの項目を変更するとメンテナンスの問題が発生する可能性があります。おそらく、中間点を見つけて、代わりにビットフラグのセットを表す整数を使用できたでしょうか。

于 2010-09-06T18:20:56.303 に答える
10

はい、それは本当に悪いことだと思います。それは防御可能な選択ですが、それはそれを正しくまたは良いものにしません。

第一正規形を破ります。

2つ目の批判は、検証やバインドをまったく行わずに、生の入力結果をデータベースに直接配置すると、SQLインジェクション攻撃にさらされる可能性があるということです。

あなたが怠惰とSQLの知識の欠如と呼んでいるのは、新生児が作られているものです。時間をかけてきちんとやって、学ぶ機会として捉えることをお勧めします。

または、そのままにして、SQLインジェクション攻撃の苦痛な教訓を学びましょう。

于 2010-09-06T18:16:09.373 に答える
7

複数値の列が必要でした。xmlフィールドとして実装できます。

必要に応じて、カンマで区切ることができます

Xqueryを使用してSQLサーバーでXMLリストをクエリします

xmlフィールドになることで、いくつかの懸念に対処できます。

CSVの場合:各値が正しいデータ型であることを確認できません:1,2,3、banana、5を防ぐ方法はありません

XMLの場合:タグ内の値を強制的に正しいタイプにすることができます


CSVの場合:外部キー制約を使用して値をルックアップテーブルにリンクすることはできません。参照整合性を強制する方法はありません。

XMLの場合:まだ問題


CSVの場合:一意性を強制することはできません:1,2,3,3,3,5を防ぐ方法はありません

XMLの場合:まだ問題


CSVの場合:リスト全体を取得せずにリストから値を削除することはできません。

XMLの場合:単一のアイテムを削除できます


CSVの場合:リスト内の特定の値を持つすべてのエンティティを検索するのは困難です。非効率的なテーブルスキャンを使用する必要があります。

XMLの場合: xmlフィールドにインデックスを付けることができます


CSVを使用する場合:リスト内の要素をカウントしたり、その他の集計クエリを実行したりするのは困難です。**

XMLの場合:特に難しいことではありません


CSVの場合:値を参照するルックアップテーブルに結合するのは困難です。**

XMLの場合:特に難しいことではありません


CSVの場合:ソートされた順序でリストを取得するのは困難です。

XMLの場合:特に難しいことではありません


CSVの場合:整数を文字列として保存すると、2進整数を保存する場合の約2倍のスペースが必要になります。

XMLの場合:ストレージはcsvよりもさらに悪い


CSVの場合:プラス多くのカンマ文字。

XMLの場合:コンマの代わりにタグが使用されます


つまり、XMLを使用すると、区切りリストに関する問題のいくつかを回避でき、必要に応じて区切りリストに変換できます。

于 2013-07-12T17:23:46.690 に答える
6

はい、それ悪いです。私の見解では、リレーショナルデータベースを使用したくない場合は、自分に合った代替案を探してください。非常に高度な機能を備えた興味深い「NOSQL」プロジェクトがたくさんあります。

于 2010-09-06T18:40:03.830 に答える
5

SQL ServerのNTEXT列でキーと値のペアのタブ区切りリストを4年以上使用していて、機能します。クエリを作成する柔軟性は失われますが、一方で、キーと値のペアを永続化/非永続化するライブラリがある場合、それはそれほど悪い考えではありません。

于 2010-09-06T18:16:38.637 に答える
0

私はおそらく中立的な立場を取るでしょう:CSVの各フィールドをデータベースの別々の列にしますが、正規化についてはあまり心配しません(少なくとも今のところ)。ある時点で、正規化が面白くなるかもしれませんが、すべてのデータが1つの列に表示されるため、データベースを使用しても実質的にメリットはありません。意味のある操作を行う前に、データを論理フィールド/列/呼び出したいものに分割する必要があります。

于 2010-09-06T18:19:35.183 に答える
0

ブールフィールドの数が固定されている場合は、それぞれにINT(1) NOT NULL(またはBIT NOT NULL存在する場合)またはCHAR (0)(null許容)を使用できます。SET(正確な構文を忘れた)を使用することもできます。

于 2018-12-01T00:20:51.070 に答える