2009-03-19 20 views
6

EDIT: alle persone che costruiscono sistemi di etichettatura. Non leggere questo. Non è quello che stai cercando. Ho chiesto questo quando non ero a conoscenza del fatto che tutti gli RDBMS hanno i propri metodi di ottimizzazione, basta usare uno schema semplice da molti a molti.Schema di codifica del database scalabile

Ho un sistema di registrazione che ha milioni di post. Ogni post può avere un numero infinito di tag associati ad esso.

Gli utenti possono creare tag con note, data di creazione, proprietario, ecc. Un tag è quasi come un post stesso, perché le persone possono pubblicare note sul tag.

Ogni associazione di tag ha un proprietario e una data, quindi possiamo vedere chi ha aggiunto il tag e quando.

La mia domanda è come posso implementarlo? Deve essere veloce ricerca post per tag, o tag per posta. Inoltre, gli utenti possono aggiungere tag ai post digitandone il nome in un campo, un po 'come la barra di ricerca di Google, che deve riempire il resto del nome del tag per te.

Ho 3 soluzioni al momento, ma non sono sicuro quale sia il migliore, o se c'è un modo migliore.

Nota che non sto visualizzando il layout delle note poiché sarà banale una volta ottenuta una soluzione adeguata per i tag.

Metodo 1. Lista concatenata

TagID in punti di post ad una lista collegata a tag_assoc, l'applicazione devono attraversare l'elenco fino Flink = 0

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

Metodo 2. Denormalizzazione

tag è semplicemente un campo VARCHAR o TEXT che contiene un array delimitato da tab di tagId: ownerId. Non può essere una dimensione fissa.

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

Metodo 3. Toxi

(da: http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html, anche stessa cosa qui: Recommended SQL database design for tags or tagging)

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

Metodo 3 solleva la questione, quanto velocemente sarà per scorrere tutti singola riga in tag_assoc?

I metodi 1 e 2 devono essere veloci per la restituzione dei tag per posta, ma per i post per tag, è necessario creare un'altra tabella di ricerca.

L'ultima cosa di cui mi devo preoccupare è l'ottimizzazione della ricerca dei tag per nome, non ho ancora funzionato.

ho fatto un diagramma ASCII qui: http://pastebin.com/f1c4e0e53

risposta

0

Bill Penso che ti ho buttato via, le note sono solo in un altro tavolo e c'è un tavolo separato con note pubblicate da persone diverse. I post hanno note e tag, ma i tag hanno anche note, motivo per cui i tag sono UNICI.

Jonathan ha ragione sulle liste collegate, non le userò affatto. Ho deciso di implementare i tag nel modo più semplice normalizzato che le carni mie esigenze:

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 ; 

Non sono sicuro quanto velocemente questo sarà in futuro, ma dovrebbe andare bene per un po 'come solo un paio di persone usa il database.

0

"Un tag è quasi come un post stesso, perché le persone possono pubblicare le note sul tag." - questa frase mi fa pensare che vuoi veramente una tabella per POST, con una chiave primaria e una chiave esterna che fa riferimento alla tabella POST. Ora puoi avere tanti tag per ogni post come lo spazio su disco lo permetterà.

che sto supponendo che non c'è alcun bisogno di molti a molti tra il POST e tag, perché un tag non viene condiviso tra i messaggi, sulla base di questo:

"Gli utenti possono creare tag che hanno le note, data di creazione, proprietario, ecc. "

Se la data di creazione e il proprietario sono condivisi, questi sarebbero due ulteriori relazioni con le chiavi esterne, IMO.

+0

I tag sono condivisi tra i post. Sono praticamente deciso sul metodo 3 ora. Ogni tabella che può contenere tag avrà un'altra tabella chiamata _tags. EG: news_tags. Sono ancora un po 'approssimativo su questo metodo, ma tutti sembrano raccomandarlo, quindi presumo che MySQL lo ottimizzerà. –

+0

"assumendo" - cattiva idea. Sapere è meglio. – duffymo

2

Ecco come lo farei:

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 

I campi in parentesi quadre sono la chiave primaria della relativa tabella.

Definire un vincolo sulla noteType in ogni tabella: posts, tag_assoc e tags. Ciò impedisce ad una determinata nota di applicarsi sia a post sia a tag, ad esempio.

Memorizzare i nomi dei tag come una stringa breve, non un numero intero id. In questo modo è possibile utilizzare l'indice di copertura [postId, tagName] nella tabella tag_assoc.

Il completamento del tag viene eseguito con una chiamata AJAX. Se l'utente digita "datab" per un tag, la tua pagina web effettua una chiamata AJAX e sul lato server, l'app interroga: SELECT tagName FROM tags WHERE tagName LIKE ?||'%'.

0

Un elenco collegato è quasi certamente l'approccio sbagliato. Certamente significa che le tue query saranno complesse o non ottimali, il che è ironico in quanto il motivo più probabile per utilizzare un elenco collegato è quello di mantenere i dati nell'ordine corretto. Tuttavia, non vedo un modo semplice per evitare il caricamento iterativo di una riga e quindi utilizzare il valore del flink recuperato per condizionare l'operazione di selezione per la riga successiva.

Quindi, utilizzare un approccio basato su tabella con normale chiave esterna ai riferimenti di chiave primaria. Quello delineato da Bill Karwin assomiglia a quello che definirei.

Problemi correlati