web-dev-qa-db-ja.com

タグをデータベースに保存するためのベストプラクティスは?

写真を分類するためにタグ(キーワード)を使ったサイトを開発しました。現在、MySQLデータベースにあるのは、次の構造のテーブルです。

image_id (int)
tag      (varchar(32))

誰かが画像にタグを付けるたびに(タグが有効で十分な票がある場合)、データベースに追加されます。タグ付きの5000以上の画像があり、タグテーブルには40000以上のエントリがあるため、これは最適な方法ではないと思います。これがパフォーマンスに影響し始めるのではないかと心配しています(まだ影響が出ていない場合)。

特定の他の画像に関連付けられたタグをフェッチする方が速いと考えて、この他の構造を検討しましたが、すべてのタグ、または最も人気のあるタグを取得したい場合は恐ろしいように見えます。

image_id (int)
tags     (text) //comma delimited list of tags for the image

これを行う正しい方法はありますか、それともどちらの方法もほぼ同じですか?考え?

24
John Dewans

多対多のテーブルを使用して、TAGレコードをIMAGEレコードにリンクします。

画像

DROP TABLE IF EXISTS `example`.`image`;
CREATE TABLE  `example`.`image` (
  `image_id` int(10) unsigned NOT NULL auto_increment,
  PRIMARY KEY  (`image_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

鬼ごっこ

DROP TABLE IF EXISTS `example`.`tag`;
CREATE TABLE  `example`.`tag` (
 `tag_id` int(10) unsigned NOT NULL auto_increment,
 `description` varchar(45) NOT NULL default '',
 PRIMARY KEY  (`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

IMAGE_TAG_MAP

DROP TABLE IF EXISTS `example`.`image_tag_map`;
CREATE TABLE  `example`.`image_tag_map` (
 `image_id` int(10) unsigned NOT NULL default '0',
 `tag_id` int(10) unsigned NOT NULL default '0',
 PRIMARY KEY  (`image_id`,`tag_id`),
 KEY `tag_fk` (`tag_id`),
 CONSTRAINT `image_fk` FOREIGN KEY (`image_id`) REFERENCES `image` (`image_id`),
 CONSTRAINT `tag_fk` FOREIGN KEY (`tag_id`) REFERENCES `tag` (`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
12
OMG Ponies

tagsidに、tagに一意の制約を設定したtagテーブルを作成し、次にphoto_tagsテーブルtag_idおよびphoto_id。タグがまだ存在しない場合にのみ、tagsテーブルにタグを挿入します。

次に、特定のタグでタグ付けされた写真の数などのクエリを実行するときに、varcharテキスト比較ではなくpkでクエリを実行します。

3
Matt Williamson

マルチタグ検索クエリでは、要求されたすべてのタグをヒットする必要があります。したがって、イメージタグセット[〜#〜] i [〜#〜]はリクエストタグセットのスーパーセットである必要があります[〜#〜] u [〜#〜]

I >= U

この複雑な比較をSQLで実装することは、各イメージを個別に修飾する必要があるため、少し難しい作業です。タグが画像ごとに一意に設定されていると仮定します。

SELECT i.* FROM images AS i WHERE {n} = (
  SELECT COUNT(*) 
  FROM image_tags AS t 
  WHERE t.image_id = i.image_id
    AND t.tag IN ({tag1}, {tag2}, ... {tagn})
)

スキーマ:

CREATE TABLE images (
  image_id varchar NOT NULL,
  PRIMARY KEY (image_id)
)

CREATE TABLE image_tags (
  image_id varchar NOT NULL,
  tag varchar NOT NULL,
  PRIMARY KEY (image_id, tag)
)
3