2013-04-15 16 views
7

Qual è il più efficiente (in termini di prestazioni di query) del design della tabella di database - lungo o largo?MySQL: long table vs wide table

Ie, questo

id size price 
1 S 12.4 
1 M 23.1 
1 L 33.3 
2 S 3.3 
2 M 5.3 
2 L 11.0 

contro questa

id S  M  L 
1 12.4 23.1 33.3 
2 3.3 5.3 11.0 

generale (mi sa) scende al confronto di prestazioni tra GROUP BY e selezionando le colonne direttamente:

SELECT AVG(price) FROM table GROUP BY size 

o

SELECT AVG(S), AVG(M), AVG(L) FROM table 

Il secondo è un po 'più lungo per scrivere (in termini di molte colonne), ma per quanto riguarda le prestazioni dei due? Se possibile, quali sono i vantaggi/svantaggi generali di ciascuno di questi formati di tabelle?

risposta

5

Prima di tutto, si tratta di due diversi modelli di dati adatti a scopi diversi.

Detto questo, mi aspetto il secondo modello sarà più veloce per l'aggregazione, semplicemente perché i dati è imballato in modo più compatto, quindi, bisogno di meno di I/O:

  • Il GROUP BY in il primo modello può essere soddisfatto da una scansione completa dell'indice {size, price}. L'alternativa all'indice è troppo lenta quando i dati sono troppo grandi per adattarsi alla RAM.
  • La query nel secondo modello può essere soddisfatta da una scansione completa della tabella. Nessun indice necessario .

Poiché il primo approccio richiede tabella + indice e il secondo solo la tabella, l'utilizzo della cache è migliore nel secondo caso.Anche se ignoriamo la memorizzazione nella cache e confrontiamo l'indice (senza tabella) nel primo modello con la tabella nel secondo modello, sospetto che l'indice sia più grande della tabella, semplicemente perché registra fisicamente lo size e ha "buchi" inutilizzati tipici per B-Trees (anche se lo stesso vale per il tavolo se è clustered).

Infine, il secondo modello non ha l'overhead di manutenzione dell'indice, che potrebbe influire sulle prestazioni INSERT/UPDATE/DELETE.

Oltre a ciò, è possibile prendere in considerazione la memorizzazione nella cache di SUM e COUNT in una tabella separata contenente solo una riga. Aggiorna sia SUM che COUNT tramite i trigger ogni volta che una riga viene inserita, aggiornata o eliminata nella tabella principale. È quindi possibile ottenere facilmente l'AVG corrente semplicemente dividendo SUM e COUNT.


Ma si dovrebbe davvero misura sugli importi rappresentativi di dati per essere sicuri.

Dal momento che non v'è clausola WHERE nella query, verrà acquisito tutte le righe. Gli indici sono utili solo per ottenere un sottoinsieme relativamente piccolo di righe della tabella (e talvolta per index-only scans). Come regola approssimativa, se sono necessari più del 10% di righe nella tabella, gli indici non saranno di aiuto e il DBMS sceglierà spesso una scansione completa della tabella anche quando sono disponibili indici.

+0

Grazie mille per la grande spiegazione! I tuoi commenti aggiuntivi alla fine sono molto utili, la mia domanda è solo un riassunto compatto di un problema più grande che sto affrontando e sicuramente li considererò da vicino. – sashkello

1

Il lungo è più flessibile in uso. Esso consente di filtrare il size ad esempio

SELECT MAX(price) where size='L' 

Inoltre, consente per l'indicizzazione sul size e sul id. Ciò accelera lo GROUP BY e tutte le query in cui altre tabelle sono unite su id e/o size come una tabella di magazzino del prodotto.

2

La prima opzione genera più righe e generalmente sarà più lenta della seconda opzione.

Tuttavia, come indicato anche da Deltalima, la prima opzione è più flessibile. Non solo quando si tratta di diverse opzioni di query, ma anche se/quando un giorno è necessario estendere la tabella con altre dimensioni, colori, ecc.

A meno che non si disponga di un set di dati molto grande o che sia necessario un tempo di ricerca ultra-veloce, Probabilmente starò meglio con la prima opzione.

Se si dispone o è necessario un set di dati di grandi dimensioni, è preferibile creare una tabella con valori di riepilogo precalcolati.