Normalmente, eu concordo com Yaakov Ellis, mas neste caso especial, há outra solução viável:
Use duas tabelas:
Table: Item
Columns: ItemID, Title, Content
Indexes: ItemID
Table: Tag
Columns: ItemID, Title
Indexes: ItemId, Title
Isso tem algumas vantagens principais:
Primeiro, torna o desenvolvimento muito mais simples: na solução de três tabelas para inserção e atualização, item
é necessário pesquisar na Tag
tabela para ver se já existem entradas. Então você tem que se juntar a eles com novos. Esta não é uma tarefa trivial.
Em seguida, torna as consultas mais simples (e talvez mais rápidas). Existem três consultas principais ao banco de dados que você fará: Saída Tags
de uma por uma Item
, desenhe uma nuvem de tags e selecione todos os itens para um título de tag.
Todas as tags para um item:
3-Tabela:
SELECT Tag.Title
FROM Tag
JOIN ItemTag ON Tag.TagID = ItemTag.TagID
WHERE ItemTag.ItemID = :id
2-Tabela:
SELECT Tag.Title
FROM Tag
WHERE Tag.ItemID = :id
Nuvem de Tags:
3-Tabela:
SELECT Tag.Title, count(*)
FROM Tag
JOIN ItemTag ON Tag.TagID = ItemTag.TagID
GROUP BY Tag.Title
2-Tabela:
SELECT Tag.Title, count(*)
FROM Tag
GROUP BY Tag.Title
Itens para uma etiqueta:
3-Tabela:
SELECT Item.*
FROM Item
JOIN ItemTag ON Item.ItemID = ItemTag.ItemID
JOIN Tag ON ItemTag.TagID = Tag.TagID
WHERE Tag.Title = :title
2-Tabela:
SELECT Item.*
FROM Item
JOIN Tag ON Item.ItemID = Tag.ItemID
WHERE Tag.Title = :title
Mas também existem algumas desvantagens: poderia levar mais espaço no banco de dados (o que poderia levar a mais operações de disco mais lentas) e não é normalizado, o que poderia levar a inconsistências.
O argumento do tamanho não é tão forte, porque a própria natureza das tags é que elas normalmente são muito pequenas, portanto o aumento do tamanho não é grande. Alguém poderia argumentar que a consulta para o título da tag é muito mais rápida em uma pequena tabela que contém cada tag apenas uma vez e isso certamente é verdade. Mas levar em conta a economia por não ter que ingressar e o fato de que você pode criar um bom índice sobre eles pode compensar isso com facilidade. Obviamente, isso depende muito do tamanho do banco de dados que você está usando.
O argumento da inconsistência também é um pouco discutível. Tags são campos de texto livre e não há operação esperada como 'renomeie todas as tags "foo" para "bar"'.
Então tldr: eu optaria pela solução de duas tabelas. (Na verdade, eu vou. Encontrei este artigo para ver se há argumentos válidos contra ele.)