Каков наиболее эффективный способ хранения тегов в базе данных?
Я внедряю систему тегов на своем веб-сайте, аналогичную той, которая используется в stackru, и мой вопрос: каков наиболее эффективный способ хранения тегов, чтобы их можно было искать и фильтровать?
Моя идея заключается в следующем:
Table: Items
Columns: Item_ID, Title, Content
Table: Tags
Columns: Title, Item_ID
Это слишком медленно? Есть ли способ лучше?
9 ответов
Один элемент будет иметь много тегов. И один тег будет принадлежать многим предметам. Для меня это означает, что вам, возможно, понадобится промежуточная таблица, чтобы преодолеть препятствие "многие ко многим".
Что-то вроде:
Таблица: предметы
Столбцы: Item_ID, Item_Title, ContentТаблица: Теги
Столбцы: Tag_ID, Tag_TitleТаблица: Предметы_ Теги
Столбцы: Item_ID, Tag_ID
Может случиться так, что ваше веб-приложение безумно популярно и нуждается в денормализации в будущем, но бессмысленно запачкать воду слишком рано.
Вы должны прочитать сообщения в блоге Филиппа Келлера о маркировке схем базы данных. Он пробует несколько и сообщает о своих результатах, как с точки зрения простоты построения общих запросов, так и с точки зрения производительности. Количество тегов, количество отмеченных элементов и количество тегов на элемент были факторами. Посты с 2005 года; Я не знаю никаких обновлений с тех пор.
На самом деле я считаю, что дестормализация таблицы тегов может быть лучшим способом продвижения вперед, в зависимости от масштаба.
Таким образом, таблица тегов просто имеет tagid, itemid, tagname.
Вы получите дубликаты тегов, но это делает добавление / удаление / редактирование тегов для определенных элементов НАМНОГО проще. Вам не нужно создавать новый тег, удалять выделение старого и перераспределять новый, вы просто редактируете тег.
Для отображения списка тегов вы просто используете DISTINCT или GROUP BY, и, конечно, вы можете подсчитать, сколько раз теги также используются легко.
Если вы не возражаете против использования нестандартных вещей, в Postgres версии 9.4 и выше есть возможность сохранить запись типа текстового массива JSON.
Ваша схема будет:
Table: Items
Columns: Item_ID:int, Title:text, Content:text
Table: Tags
Columns: Item_ID:int, Tag_Title:text[]
Для получения дополнительной информации см. Этот замечательный пост Джоша Беркуса: http://www.databasesoup.com/2015/01/tag-all-things.html
Есть более различные варианты, тщательно сравниваемые по производительности, и предложенный выше является лучшим в целом.
Вы не можете говорить о медлительности, основываясь на данных, которые вы указали в вопросе. И я не думаю, что вам стоит слишком сильно беспокоиться о производительности на этом этапе разработки. Это называется преждевременной оптимизацией.
Тем не менее, я бы предложил включить столбец Tag_ID в таблицу тегов. Обычно хорошей практикой является то, что в каждой таблице есть столбец идентификаторов.
Я бы посоветовал использовать промежуточную третью таблицу для хранения тегов<=>ассоциаций элементов, поскольку у нас есть отношения "многие ко многим" между тегами и элементами, то есть один элемент может быть связан с несколькими тегами, а один тег - с несколькими элементами. HTH, клапан.
Если пробел будет проблемой, используйте третью таблицу Теги (Tag_Id, Title), чтобы сохранить текст для тега, а затем измените свою таблицу тегов на (Tag_Id, Item_Id). Эти два значения также должны предоставлять уникальный составной первичный ключ.
Элементы должны иметь поле "ID", а теги должны иметь поле "ID" (первичный ключ, кластеризованный).
Затем создайте промежуточную таблицу ItemID/TagID и поместите туда " Perfect Index".
Схема тегов: Таблицы тегов и атрибуты:
Таблицы:
tags (each row only keeps information about a particular tag)
taggings (each row keeps information about trigger and who will receive the trigger )
activitietis_tags (each row keeps information about tag with particular activity)
tag_status (each row keeps track of a tag status)
Таблица: теги Атрибуты таблицы тегов:
id(PK)
userId(FK users)(not null)(A tag only belongs to one user, but a user can create multiple tags. So it is one to many relationships.)
genreId(FK activity_geners)(not null)
name (string) (not null)
description (string)
status (int) (0=inactive, 1=pending, 2=active, there could be more flag)
rank(int) (rank is the popularity of a particular tag), this field can be use for sorting among similar tags.)
type (int) (0=tag, 1=challenge, 2=mission)
photo(string)
visibility (int) (0=public, 2=protected, 3 = private)(private means the tag only visible to assigned users of a activity, protected means a tag only visible to all friends and followers of the creator of the tag, public means search by public, such as all admin created tag)
createdAt(timestamp for the tag was created at)
updatedAt (timestamp for the tag last time updated)
deletedAt (default value null) (timestamp when tag was deleted, we need this field because we will delete tag permanently from audit table).
Примечание: сохранение поля № 10 пригодится позже.
Таблица: теги:
Эта таблица будет использоваться для запуска, например, для трансляции ленты других пользователей или отправки им уведомления. После вставки строки в эту таблицу будет служба, которая прочитает строку и выполнит соответствующее действие по ее удалению.
Атрибуты таблицы тегов:
Id(PK)
tagId(a tagging row only belongs to a tag, but a tag can have multiple row).
taggableId (id of a user who will receive notification)
taggableType(int) (0=notification, 1=feed message)
taggerId(the person who triggered the broadcast)
taggerType(ad, activity, news)
createdAt(timestamp for the tag was created at)
Таблица: activitietis_tags
С точки зрения пользователя пользователь может создать тег после создания экземпляра действия, поэтому в приведенной ниже таблице будет храниться информация о том, какие действия имеют какие теги.
Атрибуты таблицы атрибутов тегов:
Id (PK)
activityId(FK)
tagId(FK)
Таблица: tag_status
Когда пользователь создаст тег, в этой таблице будет создана строка с tagId и статусом по умолчанию inactive / pending, администратор извлечет все теги из таблицы тегов, где status = pending / inactive, после просмотра тега, если администратор одобрил тег, затем значение статуса в таблице тегов будет одобрен, а строка tag_status будет удалена. Если администратор отклонен, значение поля статуса таблицы tag_status будет отклонено, и будет транслироваться триггер, а получатель отправит уведомление связанному пользователю этого тега с сообщением о том, что его тег отклонен.
id(PK)
senderId(Id of the user)
receiverId(Id of admin user)
createdAt(timestamp of created at)
updatedAt(timestamp of updated at)
deletedAt(timestamp of deletedAt) default value null
expiredAt (if a tag never gets approved it will expire after a certain time for removing its information from the database. If a rejected tag gets updated by user then expiredAt will reset to new future time)
status
Message (string varchar(256)) (message for user)