2009-03-19 10 views
6

EDIT: Para personas que crean sistemas de etiquetado. No leas esto No es lo que estás buscando. Le pregunté esto cuando no sabía que todos los RDBMS tienen sus propios métodos de optimización, solo usa un esquema simple de muchos a muchos.Esquema de etiquetado de base de datos escalable

Tengo un sistema de publicación que tiene millones de mensajes. Cada publicación puede tener un número infinito de etiquetas asociadas.

Los usuarios pueden crear etiquetas que tienen notas, fecha de creación, propietario, etc. Una etiqueta es casi como una publicación en sí, porque las personas pueden publicar notas sobre la etiqueta.

Cada asociación de etiquetas tiene un propietario y una fecha, por lo que podemos ver quién agregó la etiqueta y cuándo.

Mi pregunta es ¿cómo puedo implementar esto? Tiene que ser una búsqueda rápida de publicaciones por etiqueta o etiquetas por publicación. Además, los usuarios pueden agregar etiquetas a las publicaciones al escribir el nombre en un campo, algo así como la barra de búsqueda de Google, tiene que completar el resto del nombre de la etiqueta por usted.

Tengo 3 soluciones en este momento, pero no estoy seguro de cuál es la mejor, o si hay una mejor manera.

Tenga en cuenta que no estoy mostrando el diseño de las notas, ya que será trivial una vez que obtenga una solución adecuada para las etiquetas.

Método 1. lista Vinculado

TagId en puntos enviar a una lista enlazada en tag_assoc, la aplicación deben atravesar la lista hasta flink = 0

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

Método 2. Desnormalización

etiquetas es simplemente un campo VARCHAR o TEXT que contiene una matriz delimitada por tabulaciones de tagId: ownerId. No puede ser un tamaño fijo.

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

Método 3. detector Toxi

(de: http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html, también mismo aquí: Recommended SQL database design for tags or tagging)

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

Método 3 plantea la pregunta, qué tan rápido va a ser para iterar a través de cada una sola fila en tag_assoc?

Los métodos 1 y 2 deben ser rápidos para devolver las etiquetas por correo postal, pero para las publicaciones por etiqueta, se debe realizar otra tabla de búsqueda.

Lo último que tengo que preocuparme es optimizar las etiquetas de búsqueda por nombre, todavía no lo he resuelto.

hice un diagrama de ASCII aquí: http://pastebin.com/f1c4e0e53

Respuesta

0

Bill Creo que te tiré un poco, las notas están en otra mesa y hay una mesa separada con notas publicadas por diferentes personas. Las publicaciones tienen notas y etiquetas, pero las etiquetas también tienen notas, por lo que las etiquetas son ÚNICAS.

Jonathan tiene razón acerca de las listas vinculadas, no las usaré en absoluto. Decidí aplicar las etiquetas en la forma normalizada más simple que las carnes mis necesidades:

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 ; 

No estoy seguro de lo rápido que esto será en el futuro, pero debe ser bien durante un tiempo, ya que sólo un par de personas usa la base de datos

0

"Una etiqueta es casi como un post en sí, ya que los usuarios pueden publicar notas sobre la etiqueta." - Esta frase me hace pensar que realmente solo quieres una tabla para POST, con una clave principal y una clave externa que haga referencia a la tabla POST. Ahora puede tener tantas etiquetas para cada publicación como lo permita su espacio en disco.

Estoy asumiendo que no hay necesidad de muchos a muchos entre el poste y las etiquetas, ya que una etiqueta no se comparte a través de mensajes, basado en esto:

"Los usuarios pueden crear etiquetas que tienen notas, fecha de creación, propietario, etc. "

Si la fecha de creación y el propietario son compartidos, esas serían dos relaciones de clave externa adicionales, IMO.

+0

Las etiquetas se comparten en las publicaciones. Ahora estoy más o menos decidido por el método 3. Cada tabla que puede tener etiquetas tendrá otra tabla llamada _tags. EG: news_tags. Todavía estoy algo incompleto con este método, pero todos parecen recomendarlo, así que supongo que MySQL lo optimizará. –

+0

"asumiendo" - mala idea. Saber es mejor – duffymo

2

Aquí es cómo lo haría:

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 

Los campos entre corchetes son la clave primaria de la tabla respectiva.

Defina una restricción en noteType en cada tabla: posts, tag_assoc y tags. Esto evita que una nota determinada se aplique tanto a post como a tag, por ejemplo.

Almacenar nombres de etiquetas como una cadena corta, no como un número entero id. De esta forma puede usar el índice de cobertura [postId, tagName] en la tabla tag_assoc.

La finalización de la etiqueta se realiza con una llamada AJAX. Si el usuario escribe "datab" para una etiqueta, su página web realiza una llamada AJAX y, en el lado del servidor, la aplicación consulta: SELECT tagName FROM tags WHERE tagName LIKE ?||'%'.

0

Una lista vinculada es casi seguro que es el enfoque equivocado. Ciertamente significa que sus consultas serán complejas o subóptimas, lo cual es irónico ya que la razón más probable para usar una lista vinculada es mantener los datos en el orden correcto. Sin embargo, no veo una manera fácil de evitar buscar iterativamente una fila, y luego usar el valor flink recuperado para condicionar la operación de selección para la siguiente fila.

Por lo tanto, utilice un enfoque basado en tablas con la clave externa normal a las referencias de teclas principales. El bosquejado por Bill Karwin es similar a lo que describiría.

Cuestiones relacionadas