Схема MySQL и CRUD-запросы для системы тегов

#mysql #sql #database #schema #relational-database

#mysql #sql #База данных #схема #реляционная база данных

Вопрос:

Давайте представим, что у меня есть видео, и у каждого видео может быть несколько тегов (максимум 10 тегов на видео).

Я спланировал свою схему SQL, и она выглядит следующим образом:

  • videos : id , title , path ,
  • tag_rels : id , tag_id item_id (это будет указывать на videos . id ),
  • tags : id , tag ;

Хорошо, мне кажется, все в порядке.

Затем я написал SELECT , что должен получить видео, плюс теги для него.

 SELECT `videos`.`id`, `videos`.`title`, `videos`.`path`, `tags`.`tag`
FROM `videos`
JOIN `tag_rels`
    ON `tag_rels`.`item_id` = `videos`.`id`
JOIN `tags`
    ON `tags`.`id` = `tag_rels`.`tag_id`
  

Это не тестировалось или около того, потому что все это на уровне разума.

И огромной проблемой является INSERT запрос (я полагаю, запросы).

Насколько я понимаю:

  • Запрос № 1: вставить видео в videos . Это вернет первичный ключ ( videos . id ), верно?
  • Запрос № 2: выберите тег № 1 из базы данных и получите его первичный ключ,
  • Запрос № 3: если такой записи нет (на основе имени тега ( tags . tag ), выполните запрос insert и вставьте его. Цель состоит в том, чтобы получить первичный ключ этого тега,
  • Запрос № 4: вставить запись в tag_rels с pk видео и pk тега;

Итак, это один запрос на видео, как есть, плюс 2 или 3 запроса для каждого тега.

Это означает, что если видео содержит 10 тегов и (в худшем случае) ни один из этих тегов не сохранен в базе данных, это будет стоить мне 1 10 * 3 … em…. 31 запрос?!

Должен быть способ получше! Большое спасибо!

P.S. Мне не нужны повторяющиеся записи в базе данных, и я хотел бы иметь столбец used_in to tags с количеством видео, которые используют тег. В будущем…

Ответ №1:

Это похоже на случай для хранимой процедуры. Попросите хранилище создать видеоданные и список тегов. Затем выполните запросы с # 1 по # 4 внутри. Это будет намного быстрее, поскольку вам не нужно перемещать данные взад и вперед.

Вот что вам может понадобиться. Это только отправная точка, поэтому не ожидайте, что она будет компилироваться намного быстрее, чем корректно выполняться, и вам понадобятся все 10 тегов (я не думаю, что mysql может принимать массив, но кто-то может знать лучше).

 CREATE PROCEDURE insertvideo (IN videotitle CHAR(20),IN videopath CHAR(20), IN tag1 CHAR(20),IN tag2 CHAR(20), IN tag3 CHAR(20)  )
    BEGIN
      DECLARE myid INT;
      DECLARE tagid INT;
      INSERT INTO videos (title, path) VALUES ( videotitle,videopath);
      SELECT id INTO myid FROM videos WHERE title=videotitle AND path=videopath;
      SET tagid=NULL;
      SELECT id INTO tagid FROM tags WHERE tag=tag1;
      IF tagid IS NULL THEN
        INSERT INTO tags (tag) VALUES (tag1);
        SELECT id INTO tagid FROM tags WHERE tag=tag1;
      END IF;
      INSERT INTO tag_rels (tag_id, item_id) VALUES (tagid,myid);
      SET tagid=NULL;
      SELECT id INTO tagid FROM tags WHERE tag=tag2;
      IF tagid IS NULL THEN
        INSERT INTO tags (tag) VALUES (tag1);
        SELECT id INTO tagid FROM tags WHERE tag=tag2;
      END IF;
      INSERT INTO tag_rels (tag_id, item_id) VALUES (tagid,myid);
      SET tagid=NULL;
      SELECT id INTO tagid FROM tags WHERE tag=tag3;
      IF tagid IS NULL THEN
        INSERT INTO tags (tag) VALUES (tag1);
        SELECT id INTO tagid FROM tags WHERE tag=tag3;
      END IF;
      INSERT INTO tag_rels (tag_id, item_id) VALUES (tagid,myid);
    END 
  

Комментарии:

1. Можете ли вы привести мне пример этого? Я понятия не имею, как работают процедуры — никогда не использовал их раньше. Или, по крайней мере, некоторые ссылки…

2. Вот документация: dev.mysql.com/doc/refman/5.0/en/create-procedure.html

Ответ №2:

Я думаю, что ваш расчет неверен. Вам нужно будет выполнить 3 запроса независимо от количества тегов.
1. INSERT INTO Video ...
2. INSERT INTO tags(tag)
SELECT * FROM
(SELECT 'tag_1' as tag UNION SELECT 'tag_2' ...)a WHERE NOT EXISTS
(SELECT 1 FROM tags b WHERE b.tag = a.tag)

3. Предполагая, что у вас есть уникальный индекс на (tag_id, item_id), INSERT IGNORE INTO tag_rels( tag_id, item_id) SELECT tag_id, new_video_id FROM tags WHERE tags.tag IN ([new tag_list]) (new_video_id — это Video.id вы получили после вставки записи в видео)