Как ВСТАВИТЬ теги в трехтабличной системе

Хотя некоторые основные системы, такие как Joomla, хранят теги в виде текста, разделенного запятыми, в базе данных основной статьи, предпочтительнее использовать нормализованную систему из трех таблиц в виде статьи, тегов и отношения тегов (как в других, таких как Wordpress). Есть много дискуссий и вопросов о структуре и чтении; но я не смог найти лучшую команду INSERT, так как нам нужно вставить в три таблицы. Как быстро запустить этот процесс через один прогон SQL? Или нам нужно сначала вставить статью, затем каждый тег и, наконец, написать отношения?

Другой вопрос касается уникальности тегов. Основное преимущество этой системы в том, что нам нужно хранить каждый термин только один раз (затем подключаясь к соответствующим статьям). Практично ли использовать mysql UNIQUE, чтобы избежать дублирования? Или (как я где-то читал) нам нужно прочитать весь список тегов как массив, чтобы найти любое дублирование, чтобы поймать идентификатор тега и избежать сохранения термина?

Весь процесс будет состоять из трех отдельных шагов:

  1. ВСТАВЬТЕ статью
  2. ВСТАВЛЯЙТЕ теги с УНИКАЛЬНЫМИ, но независимо от их отношения
  3. Нахождение идентификатора каждого тега и установление связи с идентификатором статьи

Я прав? Причина, по которой я спросил, заключается в том, что я видел, как люди улавливают теги как массив и проводят сравнение. Для меня это очень медленно и убивает производительность, особенно для UPDATE.


person Googlebot    schedule 20.09.2011    source источник


Ответы (4)


Вы можете вставлять только в одну таблицу за раз.

Одно решение — использовать триггеры, другое — использовать транзакцию.
Первое можно использовать с любым движком, для второго требуется InnoDB или аналогичный движок.

Убедитесь, что вы поместили индекс UNIQUE в поле tag.name.

1 – Использование транзакций

START TRANSACTION;

INSERT IGNORE INTO tag (name) VALUES ('$example1', '$example2');
INSERT INTO article (title, body) VALUES ('$title','$body');
SET @article_id = LAST_INSERT_ID();
INSERT INTO tag_link (tag_id, article_id) 
  SELECT t.id, @article_id FROM tag t WHERE t.name IN ('$example1','$example2');

COMMIT;

2-Использование триггера на столе с черной дырой

Создайте таблицу типа blackhole со следующими полями.

title: varchar(255)
body: text
tag1: varchar(50) DEFAULT NULL
tag2: varchar(50) DEFAULT NULL
...
add as many tags as you want.

Добавьте триггер AFTER INSERT в таблицу черной дыры, чтобы он выполнял фактическое хранение за вас.

DELIMITER $$

CREATE TRIGGER ai_bh_newacticle_each AFTER INSERT ON bh_newacticle FOR EACH ROW
BEGIN
  INSERT IGNORE INTO tag (name) VALUES (new.tag1, new.tag2,...,new.tag25);
  INSERT INTO article (title, body) VALUES (new.title,new.body);
  SET @article_id = LAST_INSERT_ID();
  INSERT INTO tag_link (tag_id, article_id) 
    SELECT t.id, @article_id FROM tag t 
    WHERE t.name IN (new.tag1, new.tag2,...,new.tag25);
END$$

DELIMITER ;

DELIMITER $$

Теперь вы можете просто вставить статью с тегами в одно выражение:

INSERT INTO bh_newarticle (title, body, tag1, tag2, tag3) 
  VALUES ('$title','$body','$tag1','$tag2','$tag3');

Вернуться к вашему вопросу

Я прав? Причина, по которой я спросил, заключается в том, что я видел, как люди улавливают теги как массив и проводят сравнение. Для меня это очень медленно и убивает производительность, особенно для UPDATE.

Теги полезны, только если их ограниченное количество. Если вы поместите (уникальный) индекс в tag.name, поиск тега будет очень быстрым, даже с 10 000 тегов. Это потому, что вы ищете точное совпадение. И если вы очень спешите, вы всегда можете сделать таблицу тегов таблицей memory с hash index в поле name.
Я сомневаюсь, что вам стоит беспокоиться о медленности поиска тегов.

Просто убедитесь, что вы не разрешаете слишком много тегов в статье. 5 кажется хорошим началом. 10 было бы слишком много.

Ссылки
http://dev.mysql.com/doc/refman/5.0/en/create-trigger.html
http://dev.mysql.com/doc/refman/5.0/en/blackhole-storage-engine.html

person Johan    schedule 20.09.2011

Вы не можете вставить в 3 таблицы в одном операторе, но вы можете запустить 3 оператора вставки в одной транзакции.

Я не вижу проблемы с объявлением столбца тегов уникальным, поскольку вы хотите избежать дублирования. Вы всегда можете проверить, существует ли тег, прежде чем вставлять его в таблицу или еще лучше, просто upsert теги.

person Icarus    schedule 20.09.2011

Вы запускаете каждый INSERT, выдавая один запрос, нет никакого «обходного пути», и даже невозможно его существование. Итак, 3 вкладыша на 3 стола.

Если вам нужны уникальные теги, то да — лучше использовать ограничение UNIQUE, чтобы избежать дублирования.

Простая функция INSERT IGNORE MySQL должна помочь вам избежать того, существует запись или нет перед вставкой.

person N.B.    schedule 20.09.2011

есть некоторые возможности в зависимости от функциональности СУБД, т.е. хранимые процедуры вместо триггеров, могут любые другие, чтобы сделать возможной вставку с одним оператором sql, но я думаю, что это того не стоит, потому что не так критично даже вставлять во все 3 таблица в одну транзакцию... это не плохо, если статья сохраняется, но теги не сохраняются... Но, если нужно, хранимая процедура лучше всего подходит для этой задачи, потому что она допускает сложную логику, и вы также можете написать подпрограмму в вашей программе, чтобы выполнить все sql и вызвать его при необходимости в 1 строке...

вы можете создать уникальный индекс в таблице тегов в поле тега и в таблице соотношений в полях (article_id, тег).

person skazska    schedule 20.09.2011
comment
it is not bad if article is saved but tags are failed to save. Бред какой то - person Johan; 20.09.2011
comment
Почему? автор всегда может добавлять теги к своей статье (если статья сохранилась...) - person skazska; 20.09.2011
comment
теги используются для поиска статьи. Если теги могут быть потеряны, найти статью будет очень сложно. Очень плохой дизайн. Приложение должно просто работать, оно не должно требовать двойной проверки и выдержки со стороны автора статьи. - person Johan; 20.09.2011
comment
никто не говорит, что что-то должно быть потеряно, но использование транзакций означает, что если нет возможности записать данные в таблицу тегов, то содержимое статьи также НЕ будет записано в таблицу статей... в финансах или любых других делах это помогает сохранить (fin)баланс и непротиворечивость данных, но там статья имеет большую ценность, чем ее теги и должна быть сохранена, даже если сохранить теги невозможно. Конечно очень плохо если тэги потерялись, но гораздо хуже если они потерялись со статьей - person skazska; 20.09.2011