Лучшая практика для хранения тегов в базе данных? - PullRequest
23 голосов
/ 18 августа 2010

Я разработал сайт, который использует теги (ключевые слова) для классификации фотографий. Сейчас в моей базе данных MySQL есть таблица со следующей структурой:

image_id (int)
tag      (varchar(32))

Каждый раз, когда кто-то отмечает изображение (если оно является действительным и имеет достаточно голосов), оно добавляется в базу данных. Я думаю, что это не оптимальный способ сделать что-то, так как теперь, когда у меня есть более 5000 изображений с тегами, таблица тегов содержит более 40000 записей. Я боюсь, что это начнет влиять на производительность (если это еще не влияет на нее).

Я думал, что эта другая структура думает, что было бы быстрее выбрать теги, связанные с конкретным изображением, но тогда это выглядит ужасно, когда я хочу получить все теги, или, например, самый популярный:

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

Есть ли правильный способ сделать это или оба пути более или менее одинаковы? Мысли?

Ответы [ 3 ]

10 голосов
/ 18 августа 2010

Используйте таблицу «многие ко многим», чтобы связать запись 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;

TAG

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;
2 голосов
/ 23 апреля 2018

В поисковом запросе с несколькими тегами вам нужно будет нажать на каждый запрашиваемый тег. Следовательно, набор тегов изображения 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)
)
2 голосов
/ 18 августа 2010

Вы можете создать таблицу tags, которая является просто id и tag с уникальным ограничением на tag, а затем photo_tags таблица, которая имеет tag_id и photo_id. Вставляйте тег в таблицу tags, только если он еще не существует.

Тогда вы будете запрашивать pk вместо сравнения текста varchar при выполнении запросов, например, сколько фотографий помечено определенным тегом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...