2

私は最近いくつかのことを考えていて、次のシナリオのようなことを行う正しい方法は何だろうと思っていました (DB の人がそのようなことをするのは非常に一般的なことだと確信しています)。

次のような製品テーブルがあるとしましょう (MySQL):

CREATE TABLE `products` (
  `id` int(11) NOT NULL auto_increment,
  `product_name` varchar(255) default NULL,
  `product_description` text,
  KEY `id` (`id`),
  KEY `product_name` (`product_name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

ここでは異常なことは何もありません。ここで、別のテーブルにカテゴリの階層があり、製品テーブルと多対多の関係をバインドする別のテーブルがあるとしましょう - 各製品が何らかのカテゴリに属する​​ようにします (それらは省略します) 、それはここでは問題ではないため)。

ここで興味深いのは、各カテゴリが製品アイテムに追加の変数セットを要求する場合です。たとえば、コンピューター モニター カテゴリの製品には、LCD/CRT 列挙型フィールド、画面サイズ列挙型などを含める必要があります。また、他のカテゴリでは、アイスクリームにフレーバー varchar、棚保管時間 int などの他の変数があるとします。

ここでの問題は、すべての製品に共通の変数セット (id、名前、説明など) があるが、カテゴリごとに一貫していない追加の変数があることです。ただし、すべての製品は共通のセットを共有する必要があります。最終的に、それらはすべて製品グループに属しているため、たとえば SELECT * FROM products ORDER BY company_id などのクエリを実行できます (些細な例で、代表的ではないかもしれませんが、全体像がわかります)。

今、私はいくつかの潜在的な解決策を見ています:
- 製品カテゴリごとに個別のテーブルを生成し、そこに製品を適切な追加変数とともに保存します - 愚かでクエリフレンドリーではありません

- 製品テーブルは共通の変数と同じままであり、カテゴリごとに別のテーブルを作成し、追加の変数を追加しますJOIN で 2 つのテーブルをバインドする変数 - 正規化されていますが、クエリのパフォーマンスと明確性の問題 - カテゴリ (1 番目のテーブル - 製品) から製品をフィルタリングする方法と、追加の変数 (17 インチ LCD モニターなど) 用の追加のフィルター - SQL が必要です。 JOIN トリック

- 製品テーブルは同じままで、追加の変数を保持する JSON データなどを保持する別の変数タイプのテキストを追加します - コンパクトですっきりしていますが、SQL で変数をフィルタリングすることはできません

私はここで非常に明白で単純なものが欠けていることを知っています-私は正規化技術について少し錆びています:)


編集:この質問をする前に、スタックオーバーフローを検索してきましたが、成功しませんでした。ただし、質問を投稿した後、「正規化」タグの 1 つをクリックすると、同様の質問がいくつか見つかり、「一般化専門化リレーショナル デザイン」が検索されました。話の要点は、タグが実際に検索に役立つということは、私のインターネット生活の中で初めての経験にちがいないということです。まだまだですが、皆様のご意見、ご感想をお待ちしております。
edit2 : アプローチ no.2 の問題は、約 1000 の専門化が予想されることです。カテゴリには階層 (1 ~ 4 レベルの深さ) があり、エンド ノードには特殊な変数が追加されます。それらは約 1000 のオーダーで蓄積されるため、特殊なテーブルを追加して結合するのは少し現実的ではありません。
edit3 :私の場合、属性のボラティリティが非常に多いため、提案された「エンティティ属性値」は進むべき道のように見えます。クエリの悪夢がやってくる! みんなありがとう。

4

3 に答える 3

2

でこれをやっていOracleます。

次のテーブルがありました。

t_class (id RAW(16), parent RAW(16)) -- holds class hierachy.
t_property (class RAW(16), property VARCHAR) -- holds class members.
t_declaration (id RAW(16), class RAW(16)) -- hold GUIDs and types of all class instances
t_instance (id RAW(16), class RAW(16), property VARCHAR2(100), textvalue VARCHAR2(200), intvalue INT, doublevalue DOUBLE, datevalue DATE) -- holds 'common' properties

t_class1 (id RAW(16), amount DOUBLE, source RAW(16), destination RAW(16)) -- holds 'fast' properties for class1.
t_class2 (id RAW(16), comment VARCHAR2(200)) -- holds 'fast' properties for class2
--- etc.

RAW(16)sをOracle保持する場所GUID

オブジェクトのすべてのプロパティを選択する場合は、次を発行します。

SELECT  i.*
FROM    (
        SELECT  id 
        FROM    t_class
        START WITH
                id = (SELECT class FROM t_declaration WHERE id = :object_id)
        CONNECT BY
                parent = PRIOR id
        ) c
JOIN    property p
ON      p.class = c.id
LEFT JOIN
        t_instance i
ON      i.id = :object_id
        AND i.class = p.class
        AND i.property = p.property

t_property通常は検索しないもの (テキストの説明など) を保持します。

高速プロパティは、実際にはデータベース内にある通常のテーブルであり、クエリを効率的にします。これらは、特定のクラスまたはその子孫のインスタンスに対してのみ値を保持します。これは、余分な結合を避けるためです。

高速テーブルを使用して、すべてのデータをこれら 4 つのテーブルに制限する必要はありません。

あなたのタスクでは、次のようになります (簡潔にするために、GUID の代わりに角かっこで文字列を使用します)。

t_class

id親

[ClassItem] [ClassUnknown]
[ClassMonitor] [ClassItem]
【ClassLCD】 【ClassMonitor】

t_property

クラス プロパティ

[ClassItem] 価格
[ClassItem] ベンダー
[ClassItem] モデル
【クラスモニター】サイズ
[ClassLCD] マトリックスタイプ

t_宣言

id クラス
[1] [ClassLCD] -- Iiyama ProLite E1700

t_instance -- タイプ (INT、VARCHAR など) を無視して、すべての値を 1 つの列に入れます。

id クラス プロパティ値

[1] [ClassItem] 価格 $300
[1] [ClassItem] ベンダー飯山
[1] [ClassItem] モデル ProLite E1700s
[1] [ClassMonitor] サイズ 17
[1] [ClassLCD] マトリックス型 TFT

sizeANDなどを検索する複雑なクエリが必要な場合は、それらをmatrixType削除して別のテーブルを作成できます。propertyinstance

t_lcd (id RAW(16)、サイズ INT、matrixType VARCHAR2(200))

id サイズ マトリックスタイプ

[1] 17 TFT

t_declaration上記のクエリではなく、他のプロパティと結合するために使用します。

しかし、このモデルは高速テーブルがなくても実行可能です。

于 2009-03-19T15:17:29.327 に答える
0

このパターンには名前があります。それを「汎化特化」といいます。

「一般化専門化モデリング」で検索すると、これを行う方法に関する記事がいくつか表示されます。これらの記事の中には、リレーショナル モデリングと SQL に傾いているものもあれば、オブジェクト モデリングに傾いているものもあります。

于 2009-03-20T06:54:39.590 に答える