6

編集:タグ付けシステムを構築している人々へ。これを読まないでください。それはあなたが探しているものではありません。RDBMS にはすべて独自の最適化方法があることを知らなかったので、単純な多対多スキームを使用するだけで、これを尋ねました。

何百万もの投稿がある投稿システムがあります。各投稿には、無数のタグを関​​連付けることができます。

ユーザーは、メモ、作成日、所有者などを含むタグを作成できます。ユーザーはタグに関するメモを投稿できるため、タグはほとんど投稿そのものです。

各タグの関連付けには所有者と日付があるため、誰がいつタグを追加したかがわかります。

私の質問は、これをどのように実装できますか? タグまたは投稿ごとのタグで投稿をすばやく検索する必要があります。また、ユーザーはフィールドに名前を入力して投稿にタグを追加できます。これは、Google 検索バーのようなもので、タグ名の残りの部分を入力する必要があります。

現時点では 3 つの解決策がありますが、どれが最適か、またはより良い方法があるかどうかはわかりません。

タグの適切な解決策が得られれば簡単になるため、メモのレイアウトは表示していないことに注意してください。

方法 1. リンクされたリスト

post の tagId が tag_assoc のリンクされたリストを指している場合、アプリケーションは flink=0 になるまでリストをトラバースする必要があります

post:           id, content, ownerId, date, tagId, notesId
tag_assoc:      id, tagId, ownerId, flink
tag:            id, name, notesId

方法 2. 非正規化

tags は、tagId:ownerId のタブ区切り配列を含む単なる VARCHAR または TEXT フィールドです。固定サイズにすることはできません。

post:           id, content, ownerId, date, tags, notesId
tag:            id, name, notesId

方法 3. トキシ

(から: http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html、ここでも同じこと:タグまたはタグ付けのための推奨 SQL データベース設計)

post:          id, content, ownerId, date, notesId
tag_assoc:     ownerId, tagId, postId
tag:           id, name, notesId

方法 3 では、tag_assoc のすべての行を反復処理するのにどれくらいの時間がかかるかという疑問が生じます。

方法 1 と 2 は、投稿によってタグを返す場合は高速ですが、タグによる投稿の場合は、別のルックアップ テーブルを作成する必要があります。

私が心配しなければならない最後のことは、名前によるタグ検索の最適化です。私はまだそれを解決していません.

ここに ASCII ダイアグラムを作成しました: http://pastebin.com/f1c4e0e53

4

4 に答える 4

2

これが私がそれを行う方法です:

posts:          [postId], content, ownerId, date, noteId, noteType='post'
tag_assoc:      [postId, tagName], ownerId, date, noteId, noteType='tagAssoc'
tags:           [tagName], ownerId, date, noteId, noteType='tag'
notes:          [noteId, noteType], ownerId, date, content

角括弧内のフィールドは、それぞれのテーブルの主キーです。

、、およびnoteTypeの各テーブルで制約を定義します。これにより、たとえば、特定のメモが aと a の両方に適用されなくなります。poststag_assoctagsposttag

タグ名を整数ではなく短い文字列として保存しidます。そうすれば、テーブルでカバリング インデックス [ postId, tagName]を使用できtag_assocます。

タグの補完は、AJAX 呼び出しで行われます。ユーザーがタグに「datab」と入力すると、Web ページが AJAX 呼び出しを行い、サーバー側でアプリが次のクエリを実行しますSELECT tagName FROM tags WHERE tagName LIKE ?||'%'

于 2009-03-21T01:47:17.607 に答える
0

ビル、私はちょっとあなたを思いとどまらせたと思います。メモは別のテーブルにあり、別の人が投稿したメモが別のテーブルにあります。投稿にはメモとタグがありますが、タグにもメモがあるため、タグは一意です。

ジョナサンは、リンクされたリストについて正しいです.私はそれらをまったく使用しません. 私は、自分のニーズを満たす最も単純な正規化された方法でタグを実装することにしました。

DROP TABLE IF EXISTS `tags`;
CREATE TABLE IF NOT EXISTS `tags` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `owner` int(10) unsigned NOT NULL,
  `date` int(10) unsigned NOT NULL,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

DROP TABLE IF EXISTS `posts`;
CREATE TABLE IF NOT EXISTS `posts` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `owner` int(10) unsigned NOT NULL,
  `date` int(10) unsigned NOT NULL,
  `name` varchar(255) NOT NULL,
  `content` TEXT NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

DROP TABLE IF EXISTS `posts_notes`;
CREATE TABLE IF NOT EXISTS `posts_notes` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `owner` int(10) unsigned NOT NULL,
  `date` int(10) unsigned NOT NULL,
  `postId` int(10) unsigned NOT NULL,
  `note` TEXT NOT NULL,
  PRIMARY KEY (`id`),
  FOREIGN KEY (`postId`) REFERENCES posts(`id`) ON DELETE CASCADE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

DROP TABLE IF EXISTS `posts_tags`;
CREATE TABLE IF NOT EXISTS `posts_tags` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `owner` int(10) unsigned NOT NULL,
  `tagId` int(10) unsigned NOT NULL,
  `postId` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  FOREIGN KEY (`postId`) REFERENCES posts(`id`) ON DELETE CASCADE,
  FOREIGN KEY (`tagId`) REFERENCES tags(`id`) ON DELETE CASCADE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

これが将来どれだけ速くなるかはわかりませんが、データベースを使用しているのは数人だけなので、しばらくは問題ないはずです。

于 2009-03-22T01:43:20.027 に答える
0

リンクされたリストは、ほぼ確実に間違ったアプローチです。これは確かに、クエリが複雑であるか最適ではないことを意味します。リンク リストを使用する最も可能性の高い理由は、データを正しい並べ替え順序に保つことであるため、これは皮肉なことです。ただし、行を繰り返しフェッチし、取得した flink 値を使用して次の行の選択操作を条件付けすることを避ける簡単な方法はわかりません。

そのため、通常の外部キーから主キーへの参照を使用するテーブルベースのアプローチを使用してください。Bill Karwin によって概説されたものは、私が概説したものと似ています。

于 2009-03-21T17:59:00.110 に答える