完全に正規化された方法でそれを行うには、次のようなものが必要です。

MEANING_ITEM には次のインデックスがあります。
- {SITE_ID, MEANING_NO, ITEM_NO} - 主キー用に自動的に作成され、指定されたタグを持つアイテムを効率的に検索できます。
- {ITEM_NO, SITE_ID, MEANING_NO} - 「指定されたアイテムのタグを取得する」という逆のクエリを効率的に実行できます。
注: DBMS でサポートされている場合は、このテーブルをクラスタ化することを検討してください。クラスター化されたテーブルのセカンダリ インデックスはコストがかかる可能性があります (PK 全体のコピーを含める必要があり、二重ルックアップが発生する可能性があるため)。ただし、この場合、両方のインデックスに同じフィールドが含まれます (したがって、すべての「余分な」フィールドは既にセカンダリにありますindex) であり、インデックスの外側にはフィールドがないため、二重ルックアップは必要ありません。クラスタリングによって、(役に立たない) テーブル ヒープを単純に排除し、2 つの B ツリーだけが残ります。
このモデルには次のプロパティがあります。
- タグとアイテムの両方がサイト固有の方法で識別され、デフォルトでサイト固有のタグを照会します。サイトに関係なくタグ名でクエリを実行する場合は
SITE_ID = ...
、以下のクエリで WHERE 句を省略します。TAG_NAME は TAG PK の最先端にあるため、サイトレス クエリは追加のインデックスなしで効率的に満たすことができます。
- 「間違った」サイトのタグでアイテムをタグ付けすることはできません。SITE_ID を「ひし形」の依存関係の両端に伝播する識別関係を使用して、「ひし形」の下部 (MEANING_ITEM 内) でマージします。これにより、この保証が得られます。
- タグの類義語は効率的に表現されます (同じサイト内で同じ意味を持つタグは類義語と見なされます)。タグに M:N 自己関係を実装しようとした場合に発生する可能性のあるさまざまな異常の余地はありません。1
- タグの意味はサイト固有であるため、シノニムもサイト固有です。
- MEANING テーブルは、タグに関する追加情報 (説明など) を格納する自然な場所であり、すべての同義語で共有されます。
1同義語の推移性をどのように処理しますか? A、B、C が同義語の場合、AB と BC を保存するだけですか、それとも AC も保存しますか? どうやって強制するの?強制しない場合は、すべての依存関係を選択するために何らかの再帰クエリが必要になります。また、接続ごとに行が必要になり、スペースとパフォーマンスが無駄になります。
指定されたタグのいずれかを持つアイテムを取得するには、次のようなクエリを実行する必要があります...
SELECT *
FROM ITEM
WHERE EXISTS (
SELECT *
FROM TAG JOIN MEANING_ITEM ON
TAG.SITE_ID = MEANING_ITEM.SITE_ID
AND TAG.MEANING_NO = MEANING_ITEM.MEANING_NO
WHERE
TAG.SITE_ID = <site id>
AND TAG.NAME IN ( <list of tags> )
AND ITEM.SITE_ID = MEANING_ITEM.SITE_ID
AND ITEM.ITEM_NO = MEANING_ITEM.ITEM_NO
)
注: 上記のクエリから MEANING への JOIN を完全に省略できます。JOIN に必要なすべてのフィールドは既に TAG に含まれています。
指定されたすべてのタグを持つアイテムの場合、次のような COUNTing が必要になります。
SELECT *
FROM ITEM
WHERE <number of tags> = (
SELECT COUNT(DISTINCT TAG_NAME)
FROM TAG JOIN MEANING_ITEM ON
TAG.SITE_ID = MEANING_ITEM.SITE_ID
AND TAG.MEANING_NO = MEANING_ITEM.MEANING_NO
WHERE
TAG.SITE_ID = <site id>
AND TAG.NAME IN ( <list of tags> )
AND ITEM.SITE_ID = MEANING_ITEM.SITE_ID
AND ITEM.ITEM_NO = MEANING_ITEM.ITEM_NO
)
これは多くの JOIN 処理のように見えますが、このモデルはクラスター化された (インデックス構成された) テーブルや、クエリをインデックスでカバーするのに優れています。
おそらく、パフォーマンス上の理由からこの設計を非正規化することを検討する前に、実際の StackExchange のデータ量に近づく必要があります (たとえば、ジャンクション テーブルを削除し、アイテムごとのタグ数を制限するなど)。
いずれにせよ、特定の設計に取り組む前に、現実的な量のデータを測定してください。