タグまたはタグ付けに推奨されるSQLデータベース設計[終了]


288

タグ付けを実装するいくつかの方法を聞いたことがあります。TagIDとItemIDの間のマッピングテーブルを使用します(私には理にかなっていますが、それはスケールしますか?)クレイジーですが、動作する可能性があります)。誰かが疎行列を推奨することさえ聞いたことがありますが、タグ名はどのようにして優雅に成長しますか?

タグのベストプラクティスがありませんか?


9
さて、これは質問#20856です。(ほぼ)同じ質問は、この質問が出されてから少なくとも2週間後に#48475が出されます。
dlamblin 2008年

9
別の興味深い質問は、「SOがタグを実装する方法」です。
モスタファ

1
もう1つの興味深い質問は、「それらを国際化しますか?そうであれば、どのように?」
DanMan 2013

1
興味深い比較(Postgres固有):databasesoup.com/2015/01/tag-all-things.html
a_horse_with_no_name

回答:


406

適切にインデックスが作成され、外部キーセットが適切なデータベースで実行されている3つのテーブル(すべてのアイテムの格納用、1つはすべてのタグ用、1つは2つのタグ間の関係用)は、適切に機能し、適切にスケーリングされます。

Table: Item
Columns: ItemID, Title, Content

Table: Tag
Columns: TagID, Title

Table: ItemTag
Columns: ItemID, TagID

32
これは「Toxi」ソリューションとして知られており、ここで追加情報を見つけることができます:howto.philippkeller.com/2005/04/24/Tags-Database-schemas
The Pixel Developer

16
ここに示されていないものの1つは、タグテーブル内の階層的な「タグ」またはカテゴリです。これは、カテゴリとサブカテゴリはあるがタグ付けの柔軟性が必要なサイトで一般的に必要です。たとえば、レシピサイト、自動車部品サイト、ビジネスディレクトリなどです。これらのタイプのデータは通常、1つのカテゴリにしか収まらないため、タグ付けが答えですが、ネストされたセットモデルや隣接リストモデルなどを使用する必要があります。タグテーブル内。
HK1、2011年

5
上記の構造+テーブル:TagGroup列:TagGropuId、タイトルテーブル:タグ列:TagID、タイトル、TagGroupId
Thunder

css列をテーブルに追加する場合、css列をタグテーブルに追加しますか?
阿弥陀

10
@ftvs:リンクが再度壊れ、新しいリンクはhowto.philippkeller.com/2005/04/24/Tags-Database-schemas
hansaplast

83

通常、私はヤアコフエリスに同意しますが、この特別なケースでは別の実行可能な解決策があります。

2つのテーブルを使用します。

Table: Item
Columns: ItemID, Title, Content
Indexes: ItemID

Table: Tag
Columns: ItemID, Title
Indexes: ItemId, Title

これにはいくつかの大きな利点があります。

まず、開発がはるかに簡単になります。挿入と更新の3つのテーブルのソリューションでitemは、Tagテーブルを参照して、既にエントリがあるかどうかを確認する必要があります。次に、新しいものと一緒に参加する必要があります。これは簡単な作業ではありません。

次に、クエリが単純になります(おそらく高速になります)。実行する主なデータベースクエリは3つありますTags。1つItemにすべて出力、1つのタグクラウドを描画し、1つのタグタイトルにすべてのアイテムを選択します。

1つのアイテムのすべてのタグ:

3テーブル:

SELECT Tag.Title 
  FROM Tag 
  JOIN ItemTag ON Tag.TagID = ItemTag.TagID
 WHERE ItemTag.ItemID = :id

2テーブル:

SELECT Tag.Title
FROM Tag
WHERE Tag.ItemID = :id

タグクラウド:

3テーブル:

SELECT Tag.Title, count(*)
  FROM Tag
  JOIN ItemTag ON Tag.TagID = ItemTag.TagID
 GROUP BY Tag.Title

2テーブル:

SELECT Tag.Title, count(*)
  FROM Tag
 GROUP BY Tag.Title

1つのタグのアイテム:

3テーブル:

SELECT Item.*
  FROM Item
  JOIN ItemTag ON Item.ItemID = ItemTag.ItemID
  JOIN Tag ON ItemTag.TagID = Tag.TagID
 WHERE Tag.Title = :title

2テーブル:

SELECT Item.*
  FROM Item
  JOIN Tag ON Item.ItemID = Tag.ItemID
 WHERE Tag.Title = :title

しかし、いくつかの欠点もあります。データベースに多くのスペースが必要になる可能性があり(これにより、ディスク操作が多くなり、速度が低下する可能性があります)、正規化されないため、不整合が発生する可能性があります。

サイズの引数はそれほど強力ではありません。タグの本質は、通常、タグがかなり小さいため、サイズの増加が大きくないためです。タグタイトルのクエリは、各タグを1回だけ含む小さなテーブルではるかに高速であると主張できますが、これは確かに当てはまります。しかし、参加する必要がないことによる節約と、それらに優れたインデックスを構築できるという事実を考慮すると、これを簡単に補うことができます。もちろん、これは使用しているデータベースのサイズに大きく依存します。

一貫性のない議論も少し議論の余地があります。タグはフリーテキストフィールドであり、「すべてのタグの名前を "foo"から "bar"に変更」などの予期される操作はありません。

だからtldr:私は2つのテーブルの解決策に行きます。(実際、私はこれに行きます。この記事を見つけて、それに対して有効な引数があるかどうかを確認しました。)


「Index:ItemId、Title」は、各インデックスまたは両方を含む1つのインデックスを意味しますか?
DanMan 2013

通常は2つのインデックス。ただし、使用しているデータベースによって異なる場合があります。
Scheintod 2013

1
タグテーブルには、ItemIdと複合キーのタグがありますか?またはあなたはPKも持っていますか?
Rippo 2014年

2
この方法では「未使用」のタグを作成できないため、「タグの追加」機能をアイテムで実行する必要があります。もう1つの方法では、「タグの追加」機能を個別に実行できます
Gianluca Ghettini 2017

1
@Quilang。私はまだそれがあなたが何をしているかに依存すると信じています:)私はそれを異なる方法で両方の方法で実装しました。最後の1つでは、「タグタイプ」(またはタグのその他のメタ情報)が必要で、タグの近い従属からのコード(パラメーター)を再利用できるため、3テーブルソリューションになりました。しかし、まったく同じプロジェクトで、私はさらに近い従兄弟にこの方法を正確に使用しました:フラグ(たとえば、「売られた」、「新しい」、「熱い」)
Scheintod

38

couchdbのようなmap-reduceをサポートするデータベースを使用している場合、プレーンテキストフィールドまたはリストフィールドにタグを格納するのが実際に最善の方法です。例:

tagcloud: {
  map: function(doc){ 
    for(tag in doc.tags){ 
      emit(doc.tags[tag],1) 
    }
  }
  reduce: function(keys,values){
    return values.length
  }
}

これをgroup = trueで実行すると、タグ名で結果がグループ化され、タグが検出された回数のカウントが返されます。これは、テキスト内の単語の出現回数数えるのとよく似ています


4
+1いくつかのNoSQL実装もご覧ください。
Xeoncross 2011年

@NickRetallackリンクが機能していません。可能であれば、この回答を更新してください。
xralf

OKリンクをarchive.orgへのリンクに置き換えました
Nick Retallack

13

タグを格納するために単一のフォーマットされたテキスト列[1]を使用し、これをインデックス化するために対応する全文検索エンジンを使用します。そうしないと、ブールクエリを実装しようとしたときにスケーリングの問題が発生します。

持っているタグの詳細が必要な場合は、増分的に維持されるテーブルで追跡するか、バッチジョブを実行して情報を抽出できます。

[1]一部のRDBMSは、解析手順を必要としないためストレージにさらに適しているかもしれないが、全文検索で問題を引き起こす可能性があるネイティブ配列タイプを提供することさえあります。


単語のバリエーションを見つけられない全文検索エンジンを知っていますか?たとえば、本を検索すると本が返されますか?また、「c ++」のようなタグについてはどうしますか?たとえば、SQL Serverはインデックスのプラス記号を取り除きます。ありがとう。
ジョナサンウッド

Sphinxをお試しください-sphinxsearch.com
Roman

この3部構成のチュートリアルは、このルート(全文検索)を利用する人に役立つかもしれません。これは、PostgreSQLのネイティブ機能を使用します:shisaa.jp/postset/postgresql-full-text-search-part-1.html
ウィル

これは、パフォーマンスの点で選択した回答よりも優れていますか?

varchar 255、コンマ区切りのタグを使用して格納し、それにkfullテキストインデックスを追加してみませんか?

9

私はいつもタグを別のテーブルに保管し、その後マッピングテーブルを用意しました。もちろん、本当に大規模なこともしたことはありません。

「タグ」テーブルとマップテーブルがあると、タグクラウドなどを生成するのが非常に簡単になります。SQLを簡単にまとめて、各タグの使用頻度のカウントを含むタグのリストを取得できるためです。


6
マッピングテーブルを使用しない場合、これはさらに簡単です:)
Scheintod

0

次のデザインをお勧めします。アイテムテーブル:Itemid、taglist1、taglist2
これは高速で、アイテムレベルでデータを簡単に保存および取得できます。

並行して別のテーブルを作成する:タグタグはタグの一意の識別子を作成せず、次の列を含む2番目の列のスペースが不足すると、100アイテムが別の行を作成するとします。

タグのアイテムを検索している間、それは超高速になります。


en.wikipedia.org/wiki/First_normal_formこれには例外がありますが、非正規化は可能ですが、ここではできません
Dheeraj
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.