私の最初のeコマーススキーマを設計しています。私はしばらくこの件について読んでいますが、order_line_item
とproduct
の関係について少し混乱しています。
product
を購入できます。さまざまな詳細がありますが、最も重要なのはunit_price
です。
order_line_item
には、購入したproduct_id
、購入したquantity
、およびunit_price
への外部キーがあり、顧客が製品を購入した時点で使用されます。
私が読んだことのほとんどは、unit_price
のorder_line_item
を明示的に追加する必要があると述べています(つまり、product_id
を介して参照しないでください)。ストアは将来的に価格を変更し、注文レポート、追跡、整合性などを台無しにする可能性があるため、理にかなっています。
私が理解できないことは、なぜunit_price
値をorder_line_item
に直接保存するのですか?
product
のunit_price
の変更を文書化した監査/履歴テーブルを作成する方が良いでしょうか?
order_line_item
が作成されると、product_audit
テーブルの外部キーが追加され、そこから(参照により)価格を取得できます。
このアプローチを使用することには多くのメリットがあるようです(データの重複が少ない、価格変更履歴など)ので、なぜもっと頻繁に使用しないのですか?このアプローチを使用するeコマーススキーマの例を見たことがないのですが、何か不足していますか?
UDPATE:私の質問は 緩やかに変化する次元 に関連しているようです。緩やかに変化するディメンションはデータウェアハウスとOLAPに関連しているので、私はまだ混乱しています。では、緩やかに変化するディメンションタイプをメインのビジネストランザクションプロセスデータベース(OLTP)に適用できますか?たくさんのコンセプトを混ぜているのではないかと思いますが、いくつかのガイダンスをいただければ幸いです。
ご存じのとおり、注文に価格を保存すると、技術的な実装が容易になります。ただし、これが有益である理由はいくつかあります。
Webトランザクションに加えて、多くの企業が他のチャネルを介した販売をサポートしています。
これらの場合、トランザクションが実行された後、注文がシステムに入力されることがあります。このような状況では、どの履歴価格レコードを使用する必要があるかを正確に特定するのが困難から不可能に至る可能性があります。注文に直接単価を保存することが唯一の実行可能なオプションです。
複数のチャネルは、別の課題をもたらすことがよくあります-同じ製品の異なる価格。電話注文の追加料金は一般的です-一部のお客様は割引について交渉する場合があります。商品スキーマのすべてのチャネルのすべての可能な価格を表すことができる場合がありますが、これを注文テーブルに組み込むと(非常に)複雑になる可能性があります。
交渉が許可されている場合はどこでも、合意された注文価格に価格履歴をリンクすることが非常に難しくなります(エージェントの交渉制限が非常に狭い場合を除く)。注文自体に価格を保存する必要があります。
Webトランザクションのみをサポートし、料金体系が比較的単純な場合でも、克服すべき興味深い問題があります-フライト中のトランザクションではどのように価格の引き上げを処理する必要がありますか?企業は、顧客が値上げする必要があると主張していますか、それとも(製品がバスケットに追加されたときの)当初の価格を尊重していますか?後者の場合、技術的な実装は複雑です。セッションで価格バージョンを正しく維持していることを確認する方法を見つける必要があります。
最後に、多くの企業が非常に動的な価格設定を使用し始めています。特定の製品には1つの固定価格がない場合があります。これは、時刻、製品の需要などの要素に基づいて実行時に常に計算されます。これらの場合、そもそも価格が製品に対して保存されない場合があります!
私が見たいくつかの実用的なポイントを追加します。
製品は一時的です。
彼らが今日意味するかもしれないものは、彼らが1年前に意味していたものと同じでないかもしれません。同じSKUコード(つまり、product_id)は、異なる段階で製品の異なるバリアント/種類を参照する場合があります。
誰もがすべての懸念を理解しているわけではありません。したがって、ユーザーは自分の無知から新しいものを作成するのではなく、元の製品の属性を変更できます。多くの場合、これはユーザーが使用しているプランが原因で発生する可能性があります(Hey!私は100のSKUしか持てないので、プランをアップグレードするのではなく、古いSKUを変更し続けるのはなぜでしょうか)。 、製品が永遠に同じことを示すことはありません。
注文と配送条件に基づいて異なる価格
ユーザー@Chrisが述べたように、異なるシナリオでは異なる価格が適用される場合があります。
ほとんどのカートでは、少なくとも3つの異なるフィールド(単価、割引額、割引価格)が保存されています。より高度なものでは、さらに2つあります-税込みの単価、税込みの割引価格。配送方法の料金と追加の支払い方法の料金を説明するフィールドがさらに2つ表示される場合があります。税率は、州、製品、国、配送方法などによって異なり、その他の費用も異なります。同様に、割引は地域、プロモーション、販売時期などによって異なる場合があります。したがって、注文レベルでのみ取得できる情報があり、この組み合わせた情報は、製品テーブルのデータだけから生成することはできません。
関心事の分離
さまざまなチームがデータのさまざまな部分を制御できるように、多くのカートが実装されています。注文システムを管理する一部の人は、すべての製品の在庫状況、さまざまな時点での価格、特定のSKUの代替品などを常に知る必要はありません。製品関連データを注文データとともに保持することで、懸念の分離を実現できます。異なるチームがシステムの異なる部分を管理する場合、これは開発段階でも当てはまる可能性があります。
複数のシステムにわたるより容易なスケーラビリティ
多くの場合、注文管理システム、ルールエンジン、カタログエンジン、コンテンツ管理システムはすべて、独自のシステムとして構築/保守されています。これにより、さまざまな負荷条件を最適化し、システムごとに特別なインテリジェンスを生成できます。したがって、別のシステムからの情報が利用できないため、1つのシステムを身代金に留めることはできません。
開発と実行時間の短縮
ここでは「開発時間」という用語を使用しましたが、「デバッグ時間」を使用する方が適切です。新しい開発が行われるときはいつでも、独自の複雑さを追加することなく必要なデータを利用できる場合は、デバッグサイクルが比較的小さくなるため、より速くなります。
半年前の特定の月に毎日提供される割引のオンデマンドレポートを生成するように依頼されたと想像してください。あなたが元の価格、注文、注文商品の詳細とともに1-2表の割引価格を持っている場合、これはかなり簡単です。ただし、別のテーブルから価格を取得し、別のテーブルから該当する割引を取得して詳細を把握する必要がある場合は、開発時間と実行時間の両方が高くなります。
優れた設計は、現在の場合と同様に、将来についても最適化を試みるべきです。
最終的にはストレージのコストが高くなる可能性がありますが、私はトランザクションのすべての関連する詳細をトランザクション自体に格納することを好みます。これにより、何らかの理由で監査証跡が破損したり、管理者が適切な安全性を上書きしたりした場合、のような販売:使用される通貨、単価、数量、適用される税金、それらがどのような価値になるかなどがすべて利用可能です。通常はXMLとして保存するため、販売から販売まで柔軟に対応できます。
編集:私が上で簡単に言ったこと、下の私のフォローアップコメント、および@a_horse_with_no_nameが上で触れたことを拡大するために、トランザクションデータの冗長性は重要であるだけでなく、大規模にも必要です。
OOPを使用して構築していると想定しているので、トランザクションオブジェクトと、すべてを網羅する製品オブジェクトまたは価格オブジェクト、あるいはその両方が必要になる可能性があります。私の個人的な経験では、私は私の歴史の中で冗長であるのを好みます、ストレージは比較的安いです。
私たちがやったことは、既存のRDBMSまたはいくつかのフレーバーのNOSQLキー値ストア(または、より良い、handlersocketやmemcacheなどのNoSQLのような接続を許可するRDBMS)を使用して容易にできるオブジェクト履歴を作成し、オブジェクト履歴を保存することです。このようにして、すべての詳細と価格の変更を1か所で簡単かつ迅速に利用できます。深刻な場合は、DIFFを使用してストレージを節約し、変更のみを保存することもできますが、独自の注意事項があります。これで履歴が処理されます。シリアル化されたオブジェクトの利点は、システムがオブジェクトを、それらが格納されたオブジェクトとして元に戻すことができる/すべきであるということです。それは歴史を大事にする。
私の提案に関して、税金、通貨などのトランザクションの詳細をトランザクション自体に保存することは、それらの詳細を他の場所で探す必要がないことを意味します。トランザクションオブジェクトはそのプロパティを認識し、ビューで表示することができます。必要に応じて変化するデータ。スナップショットにすばやくアクセスでき、冗長で検証可能なレコードの追加の利点があります。
それは価値があります、私を信頼してください!
私の投票は、ラインアイテムの単価を保存し、別のテーブルで製品の価格履歴を追跡することです。これに対する私の正当化は、追加された柔軟性のためです。
料金体系が厳格で明確に定義されていて、@ Chris Saxonが前述したような変動を許容しない場合でも、常にそうであることに満足していますか?自信があるとしても、なぜ隅に自分をペイントするのですか?これを個別に保持する説得力のある理由が考えられないため、これを広告申込情報の詳細に保存することをお勧めします。
価格履歴の保存に関しては、アイテムの価格に変更があり、誰もそれを購入しなかった可能性があるため、個別に保存することには明確な価値があります。これは間違いなく、価格変更が効果がないかどうかを知るのに役立つ情報です。ご指摘のとおり、これはデータウェアハウスシナリオにおけるタイプ2の緩やかに変化するディメンションの従来の使用例です。通常、製品テーブルの価格変更がキャプチャされ、更新された価格とタイムスタンプを含む新しい行がディメンションテーブルに追加され、この変更がいつ行われたかを示します。前の行では、終了日が更新され、有効な価格ではなくなったことを示します。したがって、1つのアプローチは、データウェアハウスでこの種の変更を追跡することです。
ただし、OLTP eコマースデータベースの設計と同時にデータウェアハウススキーマとETLプロセスの設計に関心がない場合は、この履歴をeコマースデータベースに確実に取り込むことができます。 。これは、製品テーブルにぶら下がって、製品のそのバージョンが有効になったときの開始日と終了日を含む別個のproduct_auditテーブルを作成することで説明したように行うことができます。現在アクティブな製品を示すために、表の開始日と終了日。ただし、製品の数、会社が受ける数または価格の変更によっては、これにより、製品表が意図したよりも大きくなり、後でクエリのパフォーマンスの問題が発生する可能性がありますオン。
最後に、価格設定の履歴をラインアイテムの実際の単価から切り離すと、その時点でリストされている価格を上回った、または下回った価格で製品が販売された時期を確認する他の分析機会が確実に得られます。
注文に関連する情報(コンテキスト)をまとめておくという基本的な考えに完全に同意します。このような状況が発生するのは、データベース中心のアプリケーションを非常に多く設計し、すべてが大きなファットデータベースを中心に展開する場合のみです。別の角度から問題のドメインを見て視点を切り替えると、順序がアプリケーションのライフサイクルにおける非常に特殊なイベントのキャプチャされたスナップショットであることがはっきりとわかります。コンテキストに基づいて問題を処理すると、データベースの問題は二次的かつ複雑になり、クエリやレポートの作成について誰もが恐れているようになり、ドメインモデルでシームレスに処理されます。