2013-02-27 11 views
10

Quindi ho una tabella dei preferiti dell'utente. Ce ne sono alcuni milioni di file.Modo efficiente per memorizzare gli articoli riordinabili in un database

Attualmente, hanno solo tre colonne: id (pk), userId e someFkRef. C'è un indice su userId per permettermi di selezionare rapidamente i preferiti di un utente.

Attualmente questi sono ordinati per id che è effettivamente solo l'ordine di inserimento. Vorremmo offrire all'utente la possibilità di riordinare i preferiti, molto probabilmente tramite una sorta di interazione drag and drop.

Il mio primo (e ho il sospetto ingenuo) approccio a questo sarebbe semplicemente aggiungere una colonna order e un indice composito sopra userId, order. Tuttavia, dopo aver riflettuto, quando l'utente sposta la sua voce di una certa distanza sull'elenco, tutte le righe intermedie tra la posizione iniziale e la posizione finale dell'articolo avranno bisogno di ricalcolare la colonna order e quindi anche l'indice.

Questo è (molto probabilmente) cattivo.

Prima di impiegare anni a cercare di quantificare esattamente quanto sia grave, mi chiedo se ci sia una rappresentazione basata su tabella migliore che è più economica da manipolare con i tipi di operazioni che descrivo sopra.

+0

Non sono convinto che sia necessario indicizzare il nuovo campo. –

+0

Generalmente, 'order by' ops richiede un indice, no? – spender

+0

@spender Necessario no, ma se le righe della tabella sono grandi e si ottiene un set di risultati di grandi dimensioni, l'ordinamento utilizzando un indice potrebbe generare un numero di I/O un po 'inferiore. –

risposta

3

Se non è necessario essere in grado di manipolare alcuni FkRef attraverso gli utenti (ad esempio, ottenendo l'elenco di utenti interessati a qualcosa), allora si potrebbe avere un solo record per utente, con un elenco ordinato di alcuniFkRef (refA , refB).

Ma è una forma di de-normalizzazione, e in quanto ha alcuni svantaggi, in realtà dipende dalle vostre esigenze (e le vostre esigenze future, che è dove entra il disturbo)

+0

Sì, la denormalizzazione ti colpirà anche quando è lo stesso utente: a) devi "limitare/sfalsare" e manipolare una grande lista; b) tali dati vengono trasferiti su Internet e l'utente ordina una lista di cento elementi in modo rapido (ciao, O (N), ritardi e desincronizzazione). La denormalizzazione è un grande dolore e nessuno dovrebbe mai volerlo fare. –

6

Per un drag and drop di interazione, la scommessa migliore è una priorità. Inizierebbe con le priorità 1, 2, 3 e così via, proprio come un ordinamento.

Tuttavia, l'utente desidera spostare l'elemento 5 tra 1 e 2. Voila! Dagli il valore di 1.5. Nessun altro valore deve cambiare. L'aggiornamento dell'indice si occupa del resto.

Perché funzioni, è necessario memorizzare la priorità come numero in virgola mobile. Questo potrebbe essere un problema. Inoltre, un numero sufficientemente grande di modifiche potrebbe portare a spingere i limiti del punto mobile. Quindi, se un utente tenta di prendere l'ultimo elemento e inserirlo tra i primi due, può farla franca circa poche decine di volte.

È possibile risolvere questo problema con un processo che riassegna periodicamente il numero di uno (o tutti gli utenti, se in batch) a partire da 1.

+0

Anche questo è un approccio prezioso. Ma è ancora necessario avere un indice sulla colonna di FkRef, quindi sarà ancora un po 'consumante è la tabella è MOLTO grande. –

+1

L'indice @ SamuelEUSTACHI non è la parte peggiore. La parte peggiore è che i numeri in virgola mobile hanno una precisione finita e dopo circa 53 movimenti ben progettati si può rompere la logica degli ordini. Sì, puoi sempre avere un contatore e un trigger per rinormalizzare questo elenco, ma non sono affatto sicuro che sarà una soluzione più efficiente. –

1

Non sei sicuro di ciò che i vostri riferimenti dipendenti potrebbero essere al campo ID, ma hai pensato di sovrascriverlo? Penso che ci sia un SET IDENTITY INSERT = ON, o alcuni di quelli che puoi fare.

Mi rendo conto che è una cosa strana da suggerire, ma considerando quello che stai cercando di fare, potrebbe avere senso, e causare il minor ammontare di spese generali.

+0

@Joachim - Rinumera recordcount = 2: solo i registri del donatore e del destinatario. Reindex è indeterminato - presumibilmente ha un po 'di padding integrato e, con milioni di record, probabilmente sta reindicando fuori dal picco. – Chains