web-dev-qa-db-ja.com

さまざまなタイプのデータを単一の列に格納するための最良の方法。これはクエリに適している必要があります-MySql

私は、ユーザーがフィールドの数(最大200)を選択し、各フィールドのデータ型を定義するだけで、UIから独自のWebサービスを作成できるプロジェクトに取り組んでいます。私は同じために次のテーブル構造を検討しています:

 ServiceMaster 
 + ----------- + ------------- + ------------ -+ 
 | ServiceId | ServiceName | FieldsCount | 
 + ----------- + ------------- + ------------- + 
 | 1 | Service1 | 2 | 
 + ----------- + ------------- + ------------- + 
 | 2 | Service3 | 3 | 
 + ----------- + ------------- + ------------- + 
 
 ServiceDetails 
 + ------------------ + ----------- + ---- ---- + --------- + ------- + ------------- + 
 | ServiceDetailsId | ServiceId | Field1 | Field2 | Field3 |フィールド... 200 | 
 + ------------------ + ----------- + ------- -+ --------- + ------- + ------------- + 
 | 1 | 1 | 5 |アクティブ| NULL | NULL ... | 
 + ------------------ + ----------- + -------- + --------- + ------- + ------------- + 
 | 2 | 2 |高| 9.0 | 7 | NULL ... | 
 + ------------------ + ----------- + -------- + --------- + ------- + ------------- + 
 | 3 | 1 | 2 |実行中| 7 | NULL ... | 
 + ------------------ + ----------- + -------- + --------- + ------- + ------------- + 

クリーンでシンプルなコードのためにここにDataTypeDetailsテーブルを追加していませんが、フィールドのデータ型を保持するためのテーブルが1つあります。上記のテーブル構造を見ると、すべてのフィールドにVarcharまたは任意の文字列データ型を定義できますが、そうすると、テーブルにフィルターを適用するときに、フィールドデータを元のデータ型でキャストする必要があります。 9.0(Float)や7(Int)など。すべての列にTYPECASTINGを使用してフィルターを適用すると、クエリの速度が低下すると思います。この可能性には、数十億以上のレコードが含まれる場合があります。

それで、より良いパフォーマンスで同じことを達成するための代替方法はありますか?.

1
Shri

これは基本的にマルチテナントアプリケーションに関する質問です。また、calは、エンティティ属性値シナリオの特定のアプリケーションと見なされます。

現在のアプローチに加えて、さまざまなアプローチをとることができます。

  1. ユーザーごとに1つのServiceDetailsテーブルを持っている/サービステナントごとに)、フィールドは彼/彼女/そのニーズに応じて定義されています。クエリでは、1つではなくServiceDetails1 ... ServiceDetailsNテーブルを使用します。テーブルをDataTypeDetailsにする代わりに、データベースメタデータ(information_schema)を使用できます。必要に応じて。これは、最もクエリに適した方法です。

  2. field1, field2, ..., field200を使用する代わりに、はるかに大きなフィールドのコレクションを使用します:field1_text, field1_integer, field1_float, field1_timestamp, field2_...そして、特定のケースに適切なタイプの列のバージョンを使用します。膨大な量のNULLがあり、おそらくlotのインデックスがあります。これは(非常に大きくてまばらな)テーブルのみを使用します。通常は最善のアプローチではありませんが、可能性はあります。

  3. 変数スキーマに対してより柔軟な構造(JSONなど)を可能にするデータベースを使用します。 ( PostgreSQL JSONB インデックス付け可能なデータ型は、このシナリオに適しています。キャスト型が必要な場合でも) 。

参照:

0
joanolo

提示されたモデルに加えて、データ型ごとに個別のテーブルを追加し、それらをサービスにリンクすることもできます。このようにして、必要なフィールドのデータのみがあり、未使用の列のスペースを無駄にすることはありません。

ただし、これには多くの結合が必要であり、動的である必要がありますが、データ型を直接使用することもできます。遅いかもしれませんが、それはテストによってのみ決定できます。

また、すべてを文字列に変換して戻すのは合理的ではない可能性があるため、元の方法でのパフォーマンスよりも妥当性を重視します。

1
Sami Kuhmonen

私はこのようなテーブルを提案します:

ServiceDetails
+------------------+-----------+----------+--------+---------+---------+
| ServiceDetailsId | ServiceId | FieldNum | ValInt | ValFloat| ValChar |...
+------------------+-----------+----------+--------+---------+---------+
  1                  1           1          5        NULL      NULL
  1                  1           2          NULL     NULL      Active
  2                  2           1          NULL     NULL      High
  2                  2           2          NULL     9.0       NULL
  2                  2           3          7        NULL      NULL
  3                  1           1          2        NULL      NULL
  3                  1           2          NULL     NULL      Running
  3                  1           3          7        NULL      NULL

ValXXX列はNULL可能である必要があり、その列に使用されているデータ型のみを入力する必要があります。これにより、未使用フィールドのストレージがかなり効率的になります。

これは@joanoloの2番目の推奨事項に似ていますが、フィールド番号ごとに複数のフィールドを持つことによるテーブル行のサイズの制限にぶつかることを回避します。

0
Barmar