sql database-design tags data-modeling tagging

Diseño de base de datos SQL recomendado para etiquetas o etiquetado



database-design tags (6)

Normalmente estaría de acuerdo con Yaakov Ellis pero en este caso especial hay otra solución viable:

Utilice dos tablas:

Table: Item Columns: ItemID, Title, Content Indexes: ItemID Table: Tag Columns: ItemID, Title Indexes: ItemId, Title

Esto tiene algunas ventajas importantes:

Primero, hace que el desarrollo sea mucho más simple: en la solución de tres tablas para insertar y actualizar un item , debe buscar la tabla de Tag para ver si ya hay entradas. Entonces tienes que unirte a ellos con otros nuevos. Esta no es una tarea trivial.

Luego hace que las consultas sean más simples (y quizás más rápidas). Hay tres consultas de base de datos principales que hará: generar todas las Tags para un Item , dibujar una nube de etiquetas y seleccionar todos los elementos para un título de etiqueta.

Todas las etiquetas para un artículo:

3-tabla:

SELECT Tag.Title FROM Tag JOIN ItemTag ON Tag.TagID = ItemTag.TagID WHERE ItemTag.ItemID = :id

2-tabla:

SELECT Tag.Title FROM Tag WHERE Tag.ItemID = :id

Nube de etiquetas:

3-tabla:

SELECT Tag.Title, count(*) FROM Tag JOIN ItemTag ON Tag.TagID = ItemTag.TagID GROUP BY Tag.Title

2-tabla:

SELECT Tag.Title, count(*) FROM Tag GROUP BY Tag.Title

Artículos para una etiqueta:

3-tabla:

SELECT Item.* FROM Item JOIN ItemTag ON Item.ItemID = ItemTag.ItemID JOIN Tag ON ItemTag.TagID = Tag.TagID WHERE Tag.Title = :title

2-tabla:

SELECT Item.* FROM Item JOIN Tag ON Item.ItemID = Tag.ItemID WHERE Tag.Title = :title

Pero también hay algunos inconvenientes: podría tomar más espacio en la base de datos (lo que podría llevar a más operaciones de disco, lo que es más lento) y no se normalizará, lo que podría generar inconsistencias.

El argumento de tamaño no es tan fuerte porque la naturaleza misma de las etiquetas es que normalmente son bastante pequeñas, por lo que el aumento de tamaño no es tan grande. Se podría argumentar que la consulta para el título de la etiqueta es mucho más rápida en una pequeña tabla que contiene cada etiqueta solo una vez y esto ciertamente es cierto. Pero teniendo en cuenta los ahorros por no tener que unirte y el hecho de que puedes construir un buen índice en ellos podría compensarlo fácilmente. Por supuesto, esto depende en gran medida del tamaño de la base de datos que está utilizando.

El argumento de inconsistencia es un poco discutible también. Las etiquetas son campos de texto libre y no se espera ninguna operación como ''cambiar el nombre de todas las etiquetas "foo" a "barra"''.

Así que tldr: me gustaría ir a la solución de dos mesas. (De hecho, lo haré. Encontré este artículo para ver si hay argumentos válidos en su contra).

He oído hablar de algunas maneras de implementar el etiquetado; usando una tabla de mapeo entre TagID y ItemID (tiene sentido para mí, pero ¿es escalable?), agregando un número fijo de posibles columnas TagID a ItemID (parece una mala idea), manteniendo las etiquetas en una columna de texto que está separada por comas (suena loco pero podría funcionar). Incluso he escuchado a alguien recomendar una matriz dispersa, pero ¿cómo crecen con gracia los nombres de las etiquetas?

¿Me falta una buena práctica para las etiquetas?


Si está utilizando una base de datos que admite map-reduce, como couchdb, almacenar etiquetas en un campo de texto sin formato o en un campo de lista es la mejor manera. Ejemplo:

tagcloud: { map: function(doc){ for(tag in doc.tags){ emit(doc.tags[tag],1) } } reduce: function(keys,values){ return values.length } }

Ejecutar esto con group = true agrupará los resultados por nombre de etiqueta, e incluso devolverá un conteo de la cantidad de veces que se encontró esa etiqueta. Es muy similar a contar las ocurrencias de una palabra en un texto .


Siempre he mantenido las etiquetas en una tabla separada y luego tuve una tabla de mapeo. Por supuesto, tampoco he hecho nada a gran escala.

Tener una tabla de "etiquetas" y una tabla de mapas hace que sea bastante trivial generar nubes de etiquetas, ya que puede juntar fácilmente SQL para obtener una lista de etiquetas con conteos de la frecuencia con la que se usa cada etiqueta.


Sugeriría el siguiente diseño: Tabla de elementos: Itemid, taglist1, taglist2
esto será rápido y facilitará guardar y recuperar los datos a nivel de artículo.

En paralelo, cree otra tabla: las etiquetas de etiquetas no hacen que la etiqueta sea un identificador único y si se queda sin espacio en la segunda columna que contiene, digamos que 100 elementos crean otra fila.

Ahora, mientras se buscan artículos para una etiqueta, será súper rápido.


Tres tablas (una para almacenar todos los elementos, una para todas las etiquetas y otra para la relación entre las dos), correctamente indexadas, con el conjunto de claves externas que se ejecutan en una base de datos adecuada, deberían funcionar bien y escalarse correctamente.

Table: Item Columns: ItemID, Title, Content Table: Tag Columns: TagID, Title Table: ItemTag Columns: ItemID, TagID


Use una columna de texto con formato único [1] para almacenar las etiquetas y use un motor de búsqueda de texto completo capaz de indexar esto. De lo contrario, se encontrará con problemas de escala cuando intente implementar consultas booleanas.

Si necesita detalles sobre las etiquetas que tiene, puede realizar un seguimiento de las mismas en una tabla de mantenimiento incremental o ejecutar un trabajo por lotes para extraer la información.

[1] Algunos RDBMS incluso proporcionan un tipo de matriz nativa que podría ser incluso mejor para el almacenamiento al no necesitar un paso de análisis, pero podría causar problemas con la búsqueda de texto completo.