Mysql
 sql >> Database >  >> RDS >> Mysql

Come implementare un sistema di tagging simile a SO in php/mysql?

Prima di entrare nell'ottimizzazione prematura modalità, può essere utile esaminare il seguente modello di query. Se non altro, questo potrebbe essere utilizzato come riferimento rispetto al quale misurare l'efficacia di possibili ottimizzazioni.

SELECT T.Tagid, TagInfo.TagName,  COUNT(*)
FROM Items I
JOIN Tags TagInfo ON TagInfo.TagId = T.TagId
JOIN ItemTagMap T  ON I.ItemId = T.ItemId 
--JOIN ItemTagMap T1 ON I.ItemId = T1.ItemId
WHERE I.ItemId IN
  (
      SELECT ItemId 
      FROM Items
      WHERE   -- Some typical initial search criteria
         Title LIKE 'Bug Report%'   -- Or some fulltext filter instead...
         AND  ItemDate > '02/22/2008'
         AND  Status = 'C'
  )
--AND T1.TagId = 'MySql'
GROUP BY T.TagId, TagInfo.TagName
ORDER BY COUNT(*) DESC

La subquery è la "driving query", ovvero quella corrispondente ai criteri iniziali dell'utente finale. (vedi sotto per i dettagli su come questa query, richiesta più volte può rientrare in un flusso complessivo ottimizzato) Viene commentato il JOIN su T1 (ed eventualmente T2, T3, quando vengono selezionati più tag) e, con la clausola WHERE, l'associata criteri. Questi sono necessari quando l'utente seleziona un particolare tag, sia come parte della ricerca iniziale che per perfezionamento. (Potrebbe essere più efficiente inserire questi join e clausole where all'interno della sottoquery; maggiori informazioni su questi di seguito)

Discussione... La "domanda di guida", o una sua variazione, è necessaria per due scopi distinti:

  • 1 per fornire il completo elenco di ItemId necessario per enumerare tutti i tag associati.

  • 2 per fornire i primi N valori ItemId (N è la dimensione della pagina di visualizzazione), allo scopo di cercare le informazioni sui dettagli dell'articolo nella tabella dell'articolo.

Si noti che l'elenco completo non ha bisogno di essere ordinato (o potrebbe trarre vantaggio dall'ordinamento in un ordine diverso), mentre il secondo elenco deve essere ordinato in base alla scelta dell'utente (ad esempio per Data, discendente o per Titolo, in ordine alfabetico crescente ). Si noti inoltre che se è richiesto un qualsiasi tipo di ordinamento, il costo della query implicherà la gestione dell'elenco completo (a parte l'ottimizzazione dispari da parte di SQL stesso e/o una qualche denormalizzazione, SQL deve "vedere" gli ultimi record di quell'elenco , nel caso appartengano alla cima, in ordine di ordinamento).

Quest'ultimo fatto, è a favore di avere la stessa query per entrambi gli scopi, l'elenco corrispondente può essere memorizzato in una tabella temporanea. Il flusso generale consisterebbe nel cercare rapidamente i primi N record di articoli con i relativi dettagli e restituirli immediatamente all'applicazione. L'applicazione può quindi ottenere ajax-fashion l'elenco dei tag per i perfezionamenti. Questo elenco verrebbe prodotto con una query simile a quella sopra, in cui la sottoquery viene sostituita da "select * from temporaryTable". Le probabilità sono buone che l'ottimizzatore SQL decida di ordinare questo elenco (in alcuni casi), lasciamo che lo faccia, piuttosto che indovinarlo e ordinarlo in modo esplicito.

Un altro punto da considerare è forse portare i join sulla tabella ItemTagMap all'interno della "query di guida" piuttosto che come mostrato sopra. Probabilmente è meglio farlo, sia per le prestazioni, sia perché produrrà l'elenco giusto per lo scopo n. 2 (visualizzazione di una pagina di elementi).

È probabile che la query/il flusso sopra descritto si ridimensionerà piuttosto bene, anche su hardware relativamente modesto; provvisoriamente negli oltre 1/2 milione di articoli, con ricerche utente sostenute forse fino a 10 al secondo. Uno dei fattori chiave sarebbe la selettività dei criteri di ricerca iniziali.

Idee per l'ottimizzazione

  • [A seconda dei tipici casi di ricerca e delle statistiche dei dati] può avere senso denormalizzare portando (anzi duplicando) alcuni dei campi di Items nella tabella ItemTagMap. I campi brevi in ​​particolare potrebbero essere "benvenuti".
  • Man mano che i dati crescono nel milione di elementi, potremmo sfruttare la correlazione tipicamente forte di alcuni tag (es:in SO, PHP spesso viene fornito con MySql, tra l'altro spesso senza una buona ragione...), con vari trucchi. Ad esempio, l'introduzione di TagId "multi-Tag" potrebbe rendere un po' più complicata la logica di input, ma potrebbe anche ridurre notevolmente le dimensioni della mappa.


-- 'non è detto! --
L'architettura e le ottimizzazioni appropriate dovrebbero essere selezionate alla luce dei requisiti effettivi e dell'effettivo profilo statistico dei dati...