Как вставить теги в систему с тремя таблицами - PullRequest
3 голосов
/ 20 сентября 2011

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

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

Будет ли весь процесс в три этапа:

  1. ВСТАВИТЬ артикул
  2. Вставить теги с уникальным, но независимо от их отношения
  3. Поиск идентификатора каждого тега и установление связи с идентификатором статьи

Я прав? Причина, по которой я спросил, состоит в том, что я видел, как люди ловили теги как массив и сравнивали. Для меня это очень медленно, и убивает производительность, особенно для ОБНОВЛЕНИЯ.

Ответы [ 4 ]

4 голосов
/ 20 сентября 2011

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

Одним из решений является использование триггеров, а другим - использование транзакции.
Первый может использоваться с любым движком, последний требует 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');

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

Я прав? Причина, по которой я спросил, состоит в том, что я видел, как люди ловили теги как массив и сравнивали. Для меня это очень медленно, и убивает производительность, особенно для ОБНОВЛЕНИЯ.

Теги полезны только в том случае, если их количество ограничено. Если вы добавите (уникальный) индекс в 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

1 голос
/ 20 сентября 2011

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

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

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

1 голос
/ 20 сентября 2011

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

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

0 голосов
/ 20 сентября 2011

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

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

...