Схема масштабируемой базы данных - PullRequest
6 голосов

РЕДАКТИРОВАТЬ : Для людей, создающих системы маркировки. Не читай это. Это не то, что вы ищете. Я спросил об этом, когда не знал, что все СУБД имеют свои собственные методы оптимизации, просто используйте простую схему «многие ко многим».

У меня есть система сообщений, которая имеет миллионы сообщений. С каждым сообщением может быть связано бесконечное количество тегов.

Пользователи могут создавать теги, в которых есть заметки, дата создания, владелец и т. Д. Тег почти похож на само сообщение, поскольку люди могут публиковать заметки о теге.

У каждой ассоциации тегов есть владелец и дата, поэтому мы можем видеть, кто и когда добавил тег.

Мой вопрос: как я могу это реализовать? Это должен быть быстрый поиск сообщений по тегу или тегов по почте. Кроме того, пользователи могут добавлять теги к сообщениям, вводя имя в поле, наподобие строки поиска в Google, оно должно заполнить оставшуюся часть имени тега.

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

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

Способ 1. Связанный список

tagId в записи указывает на связанный список в tag_assoc, приложение должно просматривать список до тех пор, пока flink = 0

post:           id, content, ownerId, date, tagId, notesId
tag_assoc:      id, tagId, ownerId, flink
tag:            id, name, notesId

Метод 2. Денормализация

tags - это просто поле VARCHAR или TEXT, содержащее массив тегов с разделителями табуляции tagId: ownerId. Это не может быть фиксированный размер.

post:           id, content, ownerId, date, tags, notesId
tag:            id, name, notesId

Метод 3. Токси

(от: http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html, также то же самое здесь: Рекомендуемый дизайн базы данных SQL для тегов или тегов )

post:          id, content, ownerId, date, notesId
tag_assoc:     ownerId, tagId, postId
tag:           id, name, notesId

Метод 3 поднимает вопрос, как быстро будет проходить итерация по каждой строке в tag_assoc?

Методы 1 и 2 должны быть быстрыми для возврата тегов по почте, но для сообщений по тегу должна быть создана другая таблица поиска.

Последнее, о чем я должен беспокоиться, это оптимизация поиска тегов по имени, я еще не решил это.

Я сделал диаграмму ASCII здесь: http://pastebin.com/f1c4e0e53

Ответы [ 4 ]

2 голосов
/ 21 марта 2009

Вот как я это сделаю:

posts:          [postId], content, ownerId, date, noteId, noteType='post'
tag_assoc:      [postId, tagName], ownerId, date, noteId, noteType='tagAssoc'
tags:           [tagName], ownerId, date, noteId, noteType='tag'
notes:          [noteId, noteType], ownerId, date, content

Поля в квадратных скобках являются первичным ключом соответствующей таблицы.

Определите ограничение на noteType в каждой таблице: posts, tag_assoc и tags. Это предотвращает применение данной ноты, например, к post и tag.

Хранить имена тегов в виде короткой строки, а не целого числа id. Таким образом, вы можете использовать индекс покрытия [postId, tagName] в таблице tag_assoc.

Завершение тега выполняется вызовом AJAX. Если пользователь вводит «данные» для тега, ваша веб-страница вызывает AJAX, а на стороне сервера приложение запрашивает: SELECT tagName FROM tags WHERE tagName LIKE ?||'%'.

0 голосов

Билл Я думаю, что я вроде как тебя скинул, заметки просто в другой таблице и есть отдельная таблица с заметками, опубликованными разными людьми. Сообщения имеют заметки и теги, но теги также имеют заметки, поэтому теги УНИКАЛЬНЫ.

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

DROP TABLE IF EXISTS `tags`;
CREATE TABLE IF NOT EXISTS `tags` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `owner` int(10) unsigned NOT NULL,
  `date` int(10) unsigned NOT NULL,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

DROP TABLE IF EXISTS `posts`;
CREATE TABLE IF NOT EXISTS `posts` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `owner` int(10) unsigned NOT NULL,
  `date` int(10) unsigned NOT NULL,
  `name` varchar(255) NOT NULL,
  `content` TEXT NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

DROP TABLE IF EXISTS `posts_notes`;
CREATE TABLE IF NOT EXISTS `posts_notes` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `owner` int(10) unsigned NOT NULL,
  `date` int(10) unsigned NOT NULL,
  `postId` int(10) unsigned NOT NULL,
  `note` TEXT NOT NULL,
  PRIMARY KEY (`id`),
  FOREIGN KEY (`postId`) REFERENCES posts(`id`) ON DELETE CASCADE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

DROP TABLE IF EXISTS `posts_tags`;
CREATE TABLE IF NOT EXISTS `posts_tags` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `owner` int(10) unsigned NOT NULL,
  `tagId` int(10) unsigned NOT NULL,
  `postId` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  FOREIGN KEY (`postId`) REFERENCES posts(`id`) ON DELETE CASCADE,
  FOREIGN KEY (`tagId`) REFERENCES tags(`id`) ON DELETE CASCADE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

Я не уверен, насколько быстро это будет в будущем, но какое-то время все будет хорошо, поскольку база данных используется только парой человек.

0 голосов
/ 21 марта 2009

Связанный список - почти наверняка неправильный подход. Это, безусловно, означает, что ваши запросы будут либо сложными, либо неоптимальными - что иронично, поскольку наиболее вероятная причина использования связанного списка - это сохранение данных в правильном отсортированном порядке. Однако я не вижу простого способа избежать итеративной выборки строки, а затем использовать полученное значение flink для подготовки операции выбора для следующей строки.

Итак, используйте табличный подход с обычным внешним ключом к ссылкам первичного ключа. Тот, что обрисовал в общих чертах Билл Карвин, выглядит примерно так, как я бы обрисовал.

0 голосов
/ 20 марта 2009

«Тег почти похож на само сообщение, потому что люди могут публиковать заметки о теге». - эта фраза заставляет меня думать, что вы действительно хотите одну таблицу для POST с первичным ключом и внешним ключом, который ссылается на таблицу POST. Теперь вы можете иметь столько тегов для каждого сообщения, сколько позволит дисковое пространство.

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

"Пользователи могут создавать теги, в которых есть заметки, дата создания, владелец и т. Д."

Если дата создания и владелец являются общими, это будут два дополнительных отношения внешнего ключа, IMO.

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