Способы реализации тегов - за и против каждого

Связанный

Используя SO в качестве примера, что является наиболее разумным способом управления тегами, если вы ожидаете, что они будут часто меняться?

Способ 1: Серьезно денормализованный (с разделителями-запятыми)

table posts
+--------+-----------------+ 
| postId | tags            |
+--------+-----------------+
|   1    | c++,search,code |

Здесь теги разделены запятой.

Плюсы. Теги извлекаются сразу с помощью одного запроса select. Обновление тегов прост. Легко и дешево обновить.

Минусы: дополнительный синтаксический анализ при поиске тегов, трудно подсчитать, сколько сообщений использует теги.

(альтернативно, если ограничено чем-то вроде 5 тегов)

table posts
+--------+-------+-------+-------+-------+-------+
| postId | tag_1 | tag_2 | tag_3 | tag_4 | tag_5 |
+--------+-------+-------+-------+-------+-------+
|   1    | c++   |search | code  |       |       | 

Способ 2: "Немного нормализованный" (отдельная таблица, без пересечения)

table posts
+--------+-------------------+
| postId | title             |
+--------+-------------------+
|   1    | How do u tag?     |

table taggings
+--------+---------+
| postId | tagName |
+--------+---------+
|   1    | C++     |
|   1    | search  |

Плюсы. Легко видеть количество тегов (count(*) from taggings where tagName='C++').

Минусы: tagName будет повторяться много раз.

Путь 3: Холодный малыш (нормализованный с таблицей пересечений)

table posts
+--------+---------------------------------------+
| postId | title                                 |
+--------+---------------------------------------+
|   1    | Why is a raven like a writing desk?   |

table tags
+--------+---------+
| tagId  | tagName |
+--------+---------+
|   1    | C++     |
|   2    | search  |
|   3    | foofle  |

table taggings
+--------+---------+
| postId | tagId   |
+--------+---------+
|   1    | 1       |
|   1    | 2       |
|   1    | 3       |

Профи:

  • Нет повторяющихся имен тегов.
  • Вам понравятся больше девушек.

Минусы: дороже менять теги, чем путь №1.

Ответ 1

Эти решения называются mysqlicious, scuttle и toxi.

В этой статье сравниваются преимущества и недостатки каждого из них.

Ответ 2

Я бы сказал, что есть четвертое решение, которое является вариацией вашего третьего решения:

Create Table Posts
(
    id ...
    , title ...
)
Create Table Tags
(
    name varchar(30) not null primary key
    , ...
)

Create Table PostTags
(
    PostId ...
    , TagName varchar(30) not null
    , Constraint FK_PostTags_Posts
        Foreign Key ( PostId )
        References Posts( Id )
    , Constraint FK_PostTags_Tags
        Foreign Key ( TagName )
        References Tags( Name )
        On Update Cascade
        On Delete Cascade
)

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

Ответ 3

Я лично одобряю решение №3.

Я не согласен с тем, что решение №1 легче прописывать. Подумайте о ситуации, когда вам нужно изменить имя тега.

Решение № 1:

UPDATE posts SET tag = REPLACE(tag, "oldname", "newname") WHERE tag LIKE("%oldname%")

Решение № 3:

UPDATE tags SET tag = "newname" WHERE tag = "oldname" 

Первый из них более тяжелый.

Также вы должны иметь дело с запятыми при удалении тегов (хорошо, это легко сделать, но все же сложнее, просто удалив одну строку в таблице taggings)

Что касается решения № 2... не является ни рыбой, ни птицей

Ответ 4

Я думаю, что SO использует решение # 1. Я бы пошел С# 1 или # 3.

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

Ответ 5

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

+--------+-------+-------------------------------------+
| postId | label | value                               | 
+--------+-------+-------------------------------------+
|   1    | tag   |C++                                  |
+--------+-------+-------------------------------------+
|   1    | tag   |search                               | 
+--------+-------+-------------------------------------+
|   1    | tag   |code                                 |
+--------+-------+-------------------------------------+
|   1    | title | Why is a raven like a writing desk? |
+--------+-------+-------------------------------------+ 

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