web-dev-qa-db-ja.com

個別の行としてではなく、1つの行の1つのフィールドに複数の値を格納することの利点

前回の毎週のミーティング中に、データベース管理の経験がない人がこの質問を持ち出しました。

「データを複数行ではなくインライン(文字列)で保存することを正当化するシナリオはありますか?」

国の州を保存するcountryStatesというテーブルがあるとします。この例では米国を使用します。怠惰にするためにすべての国をリストするわけではありません。

そこには2つの列があります。 1つはCountryと呼ばれ、もう1つはStatesと呼ばれます。 ここ で説明され、@ srutzkyの answer で提案されているように、PKISO 3166-1 alpha-3

テーブルは次のようになります。

+---------+-----------------------+-------------------------------------------------------+
| Country | States                | StateName                                             |
+---------+-----------------------+-------------------------------------------------------+
| USA     | AL, CA, FL,OH, NY, WY | Alabama, California, Florida, Ohio, New York, Wyoming |
+---------+-----------------------+-------------------------------------------------------+

友人の開発者に同じ質問をするとき、彼はデータトラフィックのサイズの観点から、これは役立つかもしれませんが、このデータを操作する必要がある場合はそうではないと述べました。この場合、リスト内のこの文字列を変換できるアプリケーションコードにインテリジェンスが必要です(このテーブルにアクセスできるソフトウェアがコンボボックスを作成する必要があるとしましょう)。

このモデルはあまり役に立たないと結論付けましたが、これを有効にする方法があるのではないかと疑いました。

私が尋ねたいのは、あなたが誰かが本当に動作する方法でこのような何かを見たり聞いたりしたりしていないかどうかです

11
Human_AfterAll

まず、「データを列ではなく文字列として保存する」という現在の質問のタイトルは少し混乱しています。データを他の文字列としてではなく文字列として格納することについて話すとき、それは通常、すべてを適切な/強いデータ型ではなく文字列形式にシリアル化することを指します(例:INTまたはDATETIME)。しかし、個別の行ではなく単一のフィールドに複数の値としてデータを格納することについて質問する場合、それは少し異なります。公平を期すために、値の連結は文字列を使用すると最も簡単に実行できますが、INTおよびBINARYタイプを使用して、ビットマスキングまたは同様に特定の位置を予約することによっても実行できます。異なる意味。 2番目の解釈は実際に尋ねられているものなので、質問のテキストに基づいて、それを取り上げましょう。

つまり、いいえ。実際のデータポイントを格納している場合は、不要な複雑化のため、(コードとパフォーマンスの観点から)痛みをもたらすだけです。これが単一のユニットとしてのみ保存され、単一のユニットとして更新され、データベース内で分解されない値である場合、画像またはPDFの保存とほぼ同じなので、問題はありません。それ以外の場合、データを解析しようとすると、インデックスを使用して無効になります(例:LIKE '%something%'、またはCHARINDEX、またはPATINDEX、またはSUBSTRINGなど)。

単一の行の単一のフィールドに個別の値を格納する必要がある場合は、それを行うためのより適切な方法があります。XMLまたはJSONです。これらは解析可能な形式( [〜#〜] xml [〜#〜] / [〜#〜] json [〜#〜] )であり、XMLは- インデックス付き 。しかし、理想的には、このデータは適切に入力されたフィールドに格納され、本当に役立つようになります。

また、RDBMSの目的は、データを取得およびして、課せられた制約内で可能な限り効率的に操作できるようにデータを格納することであることを忘れないでください。 [〜#〜] acid [〜#〜] に準拠することによって。最初に値を解析する必要があるため、連結された値を取得するのは十分に良くありません。これはインデックス化できません。ただし、多くの場合、操作とは、その一部を更新するためだけにblob全体を置き換えることを意味します(REPLACE関数で使用するパターンが存在しない場合)。 XMLデータ型では、少なくとも XML DML を使用して単純化した更新を行うことができますが、適切にモデル化されたデータの単純な更新ほど高速ではありません。

また、上記の質問に示されているようなシナリオで、すべてのStateCodeを連結すると、これらの値を(どちらの方向にも)外部キーにできなくなります。

また、ビジネス要件が時間の経過とともに変化し、これらのアイテムの追加のプロパティを追跡する必要がある場合はどうでしょうか。 「州」に関して、首都、人口、ソート順、またはその他についてはどうですか?行として適切に保存され、プロパティを追加するために列を追加できます。もちろん、|StateCode,Capital,Population |StateCode,Capital,Populate|...のように、解析可能なデータのレベルを複数持つことができますが、問題が指数関数的に制御不能に増大しているのを誰もが見ることができれば幸いです。もちろん、この特定の問題は、XMLおよびJSON形式でかなり簡単に処理できます。これは、前述のようにそれらの値です。しかし、これらのいずれかをモデリングの最初の手段として使用するためのvery十分な理由が依然として必要です。別の行。

13
Solomon Rutzky

私は実際にそのようなものを非常に限られた目的で使用しました。出力ファイルのヘッダーのテーブルを作成しました。それらは特別に構築されており、ほとんどが列見出しでしたが、完全ではありませんでした。したがって、データは次のようになりました

OutputType   OutputHeader
PersonalData Name|Address|City|State|Zip
JobInfo      Name|JobName|JobTitle

本質的には、区切られたリストのように見えました。そして、ある意味ではそうでした。しかし、私たちの目的のために、それは単一の長い文字列でした。

それがここのトリックです。 neverリストの解析を計画している場合は、リストを保存する価値があります。ただし、リストを解析する必要がある場合、またはリストを解析する必要がある場合は、リストを分割して別の行に保存するための余分なスペースと時間の価値があります。

9
Kenneth Fisher

たとえば、かなり小さいテーブルで一度使用しました。

CREATE TABLE t1 (
  ID number,
  some_feature   varchar2(100),
  valid_channels  varchar2(100));

CREATE TABLE channel_def (
  channel varchar2(100));

次に、値CRM,SMS,SELF-CAREvalid_channelに格納します。

テーブル全体には、10レコードのようなものがあります。 valid_channelには、多対多の関係を表すリンクテーブルに実際にある値が含まれています。テーブルt1は頻繁には使用されないため、この道を進むことにしました。しかし、いくつかの政治がこの決定に関与しました(以下を参照)。

しかし、一般的に私はそれを避けます、それは3NFではありません。

私が現在働いている場所には、何十ものそのような柱があります。彼らの正当化は、それが彼らのクエリをより簡単にするということです:リンクテーブルを使用して3つのテーブルを結合する代わりに、LIKEを使用して定義テーブルに直接行くことができます。例えば。

SELECT * 
  FROM t1 
 INNER JOIN channel_def cd
    ON ','||t1.valid_channels||',' LIKE '%,'||cd.channel||',%';

恐ろしい+ Oracleでは、'%,'を開始するため、インデックスの使用が無効になります。

1
Robotron

これはSEで行われました。 Marc Gravellとして writes

...いくつかの検討と検討の結果、パイプ(バー)で区切られた自然な表現で、先頭/末尾のパイプが決まったため、「。net c#」は単に「| .net | c#|」になります。これには利点があります:

  • 解析が非常に簡単
  • タグの一括更新と削除は、単純な置換で実行できます(パイプを含め、タグの中間一致の置換を回避します)。
  • ...

この "新しい形式"は、少し異なる "古い形式"の次のステップであり、SQL Serverのフルテキスト検索機能を利用するために選択されたため、ゼロから行う場合、いくつかの利点は関係ありません。

彼らはおそらく、作業量とパフォーマンスの両方の理由で、事物を完全に正規化しなかったと思われます。

1
Eugene Ryabtsev

文字列やその他のデータ型を使用する主な利点の1つは、純粋なパフォーマンスが必要な場合に、SQLCLRを使用してSQL ServerからC#、C、C++(など)に送信することです。ビューまたはストアドプロシージャを作成して、リレーショナルデータを非リレーショナルに表すこともできます。これは、まさにこの目的のための上記の例と同じです。

この例を見てください:

http://aboutsqlserver.com/2013/07/22/clr-vs-t-sql-performance-considerations/

ウィキペディアごと:SQL CLRまたはSQLCLR(SQL共通言語ランタイム)は、SQL Server内でMicrosoft .NET共通言語ランタイムエンジンをホストするためのテクノロジーです。 SQLCLRを使用すると、マネージコードをMicrosoft SQL Server環境でホストして実行できます。

0
Sting

私の見解では、答えはノーです。私はこのアプローチを使用していなかったので、回避しました。そのルートを下る理由を考えることができません。あなたは配列を使ってJSON/NoSQLの世界に傾いています。

以前の役割でも同様の設計の選択肢があり、建築家チームは区切られてバイナリに変換された「データ」フィールドが必要でした。いくつかの理由により、最終的にそのルートを下ることはありませんでした。

このタイプのデータに参加する必要がある場合、1つの醜い経験になります。文字列の単一の要素を更新することも不快です。

0
Clive Strong