私はインデックス作成やパーティション分割について尋ねているのではなく、大きなノーを追加するかどうかの選択について尋ねています。列の代わりに、データを行として追加することができます。説明: 現在、複数のプロパティを処理する設計を作成するように要求されており、一部の特定の製品製品の値は 1 億レコードに達し、各製品には複数のプロパティがある可能性があるため、ProductProperties のテーブルは数十億に達する可能性があります。プロパティを ProductProperties テーブル、Property1 と value1、Property2 と value2 などの列として追加することを考えた人もいます。製品がプロパティの値を保持していない場合、このプロパティの関連フィールドは null になります。また、約 80 ~ 100 のプロパティを追加して、幅広いプロパティを動的にカバーできるようにします。これは良い設計ではないため、アーキテクトはこのアプローチを拒否しました。優れたデザインと優れたパフォーマンスを実現する方法を教えてください。ありがとう
3 に答える
この問題は、さまざまな形で現れます。あなたの場合、さまざまな製品があり、それぞれに異なるプロパティ セットがあるようです。新しい製品をシステムに追加できるように、これらのプロパティを拡張可能な方法で保存する方法が必要だと思います。
アプローチ 1: 行の汎用フィールド + 補足メタデータ
あなたが提案した最初のアプローチは、製品プロパティのメタデータを独自のテーブルに正規化することで、わずかに変更できます。
いくつかの汎用フィールド (Code1、Code2、IntVal1、IntVal2、FloatVal1 ...) を使用して製品テーブルを作成します。
製品テーブルのどの列にどの属性が含まれているかについてのガイドを持つ、親子参照テーブル
ProductType
および(またはそのようなもの) の補足セットを作成します。ProductAttribute
これをアプリケーションのデータ アクセス層に解釈する機能を構築します。
これの主な利点は、構造が効率的にクエリできることです。欠点はproduct
、補助メタデータがないとテーブルの内容が不透明になることです。ただし、通常、他のアプローチの非効率性と複雑さは、この欠点を根本的に上回っています。
異なる製品タイプの数が比較的少ない場合は、メタデータを使用して、メタデータを解釈する製品テーブルのビューまたは一連のビューを生成することもできます。これにより、不透明度に関する多くの問題が軽減されます。
もう 1 つの利点は、製品に対して複数のフィルター条件を使用するクエリで、非常に大きな子テーブルに対して複数の結合を行う必要がないことです。テーブルの個々のフィールドが NULL 可能である場合、各フィールドのオーバーヘッドは比較的小さくなります (プラットフォームによっては、通常、列ごとに 1 バイト)。未使用のフィールドは、レコードのわずかなスペースを浪費します。
アプローチ 2: エンティティ属性値
これは、このクラスの問題に対する解決策としてよく提案されます。この場合Product
、ProductAttribute
親子関係にあるテーブルと、製品タイプに対して製品属性タイプをフィルタリングするいくつかの参照データがあります。
このアプローチは概念的には洗練されており、拡張可能ですが、クエリが面倒で非効率的であり、かなり多くのディスク領域を占有します。パフォーマンスの問題を軽減するために、いくつかのデータベース設計ハックをさまざまなプラットフォームで使用できます。使用している DBMS プラットフォームを指定していないため、これについて正しい方向を示すのは困難です。EAV 構造の主な長所と短所は次のとおりです。
データベースのスキーマを変更する必要がない無限の柔軟性 (+)
特に複数の属性でフィルタリングする場合 (-)
より多くのディスク容量の使用。(-)
一般に、やむを得ない要件がない限り、EAV 構造は推奨されません。
アプローチ 3: XML フィールド
Fredrick Lundh の言葉を言い換えると、「今、あなたには 2 つの問題があります」。XML フィールドは無限に拡張可能です。必要なものは何でも入れることができますが、アプリケーション以外には不透明であり、クエリが遅く、手間がかかります。SQL クエリで XML フィールドからデータを取得するのは、列に格納されたデータを取得するよりもはるかに手間がかかります。
一般に、データベース内の XML フィールドを使用して、本質的に XML ドキュメントではないものを格納することはお勧めできません。多くの人が、データベースで XML フィールドを悪用することの無知について書いています。XML フィールドからデータを抽出する ETL プロセスを構築した私の個人的な経験から、私は同意します。やむを得ない理由がない限り、避けるのが最善です。
結論
アプローチ 1 は、最初に提案したものと似ていますが、列のメタデータを独自の構造に移動します。見た目はエレガントではありませんが、ほとんどすべての場合に最適な方法です。
2つのテーブルを作成します:Product
とProductProperties
。
Product
単一の製品の基本的なプロパティが含まれます。name
、、などweight
のアイテム間で必要かつ共通の種類のもの。selling_quantity
ProductProperties
他のすべてが含まれます。プロパティの属性を正規化し、名前を付けてテーブルを作成します。必要なのはFKProduct
だけで、準備は完了です。テーブル間の1:nの関係は、ほとんどのプロパティが空の場合に80以上のプロパティを持つ単一のテーブルを持つよりもはるかに優れています(すべての製品に80〜100のプロパティが必要かどうかは疑わしいですが、リストしている製品の種類はわかりません) 。
何十億もの行を直接使用した経験はありませんが、データベースは空の列で埋めるのではなく、正規化する必要があります。この答えは私の考えをサポートしているようです:最適なデータベース構造-空のフィールドまたはテーブルの数が多い「より広い」テーブル?
最初の問題は、ProductProperties
テーブルに処理できるよりも多くの行がある場合に発生すると思いますunsigned bigint
。しばらく時間がかかるかもしれませんが、私は願っています...
既存の回答は正しく、非常に優れています。ここに新しい考え方があります。明らかに、設計を 2 つのテーブル (Products、ProductAttributeValues) に分割することが、これを行うための最も正規化された正しい方法です。
しかし、パフォーマンスはアーキテクチャの純粋さに勝る可能性があります。重要な唯一の設計目標は、ソリューション全体のコストを最小限に抑えることです。他には何もありません。非正規化されたスキーマによってパフォーマンスが十分に向上し、他の場所でパフォーマンスの労力を節約できる場合、またはハードウェアのコストが削減される場合は、それを行うのが正しいことです。TCO だけが重要です。それは簡単です。
長期的にも作業を節約する場合、またはハードウェアを節約する場合は、非正規化します。