#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 вы получили после вставки записи в видео)