Quando utilizzare TINYINT su INT?


91

In generale, utilizzo sempre Ints. So che in teoria questa non è la migliore pratica, dal momento che è necessario utilizzare il tipo di dati più piccolo che sarà garantito per archiviare i dati.

Ad esempio, è meglio usare tinyintquando si sa che gli unici dati che verranno archiviati sono 1, 0 o null (con una probabilità molto piccola di estenderli a 2 o 3 in seguito).

Tuttavia, l'unica ragione che conosco per fare questo è per scopi di archiviazione - utilizzando 1 byte su una riga anziché 4 byte.

Quali sono gli impatti dell'utilizzo tinyint(o smallintpersino bigint) solo intoltre a risparmiare spazio sul disco rigido?


2
Questo è un quesiton molto bello (+1). MySQL ha SELECT ... PROCEDURE ANALYZE () che in realtà raccomanda i tipi di dati più piccoli che la tabella dovrebbe avere per il SELECT selezionato. Questa è stata in parte l'ispirazione alla base della mia risposta.
RolandoMySQLDBA,

3
Bella domanda, ma per la precisione la gamma minuscola è 0-255. Il campo bit è 0 o 1 (o NULL). Il costo di archiviazione per un tinyint è di 1 byte. Ogni campo a 8 bit in una tabella avrà un costo di 1 byte di memoria. msdn.microsoft.com/en-us/library/ms187745.aspx e msdn.microsoft.com/en-us/library/ms177603.aspx
billinkc

@billinkc Right. Questo è il motivo per cui ho citato la possibilità di espandere la colonna per includere i valori 2 o 3. Se includi 2 o 3, devi usare tinyint (alla scala più piccola).
Richard,

1
"Ad esempio, è meglio usare tinyint quando si sa che gli unici dati che verranno archiviati sono 1, 0 o null (con una possibilità molto piccola di estenderli a 2 o 3 in seguito)." Userei un ENUM per una cosa del genere. Questi sono memorizzati come bitfield e, come molti altri hanno sottolineato qui, piccoli risparmi per record si sommano a grandi risparmi sull'intero database - anche se la colonna è indicizzata.

2
@ user6665 I'd use an ENUM for such a thing.Non in SQL Server, non lo faresti, poiché non ha enumerazioni di alcun tipo.
underscore_d,

Risposte:


92

Lo spazio su disco è economico ... non è questo il punto!

Smetti di pensare in termini di spazio di archiviazione, pensa invece al pool di buffer e alla larghezza di banda di archiviazione . All'estremo, cache della CPU e larghezza di banda del bus di memoria . L'articolo collegato fa parte della serie che evidenzia problemi con una scarsa selezione delle chiavi in ​​cluster (INT vs GUID vs Sequential GUID) ma evidenzia la differenza che i byte possono fare.

Il messaggio prioritario riguarda le questioni di progettazione. La differenza non verrà visualizzata in un singolo database su un server adeguatamente specificato fino a quando non si raggiunge il territorio VLDB ma se è possibile salvare alcuni byte, perché non farlo.

Mi viene in mente l'ambiente descritto in una domanda precedente . Oltre 400 database, con dimensioni comprese tra 50mb e 50 GB, per istanza SQL. Scrubbing di pochi byte per record, per tabella, per database in quell'ambiente potrebbe fare una differenza significativa.


29

Oltre alle altre risposte ...

Le righe e le voci di indice sono memorizzate in 8k pagine. Quindi un milione di righe a 3 byte per riga non è 3 MB sul disco: influisce sul numero di righe per pagina ("densità di pagina").

Lo stesso vale per nvarchar a varchar, smalldatetime a datetime, int a tinyint ecc

Modifica, giugno 2013

http://sqlblog.com/blogs/joe_chang/archive/2013/06/16/load-test-manifesto.aspx

Questo articolo afferma

I criteri importanti sono la cardinalità e il rapporto da pagina a riga.

Quindi, la scelta del tipo di dati è importante


5
Buon punto. Un esempio assolutamente peggiore è una riga di 4028 byte costituita da colonne di lunghezza completamente fissa a cui si desidera aggiungere una colonna. L'aggiunta di un smallint ti porterebbe a 4030 (2 righe per pagina) ma un int ti spinge oltre il limite (1 riga per pagina, 4028 byte sprecati per pagina).
Mark Storey-Smith,

Una volta ho fatto un test delle prestazioni su int vs bigint. Salvataggio di 1 milione di record, confronto di tempo e archiviazione e recupero uno per uno, misurando nuovamente le prestazioni. Non ho visto grandi differenze. Farò lo stesso test delle prestazioni per int vs tinyint. Penso davvero che possa essere trascurato per l'80% delle applicazioni, dando luogo a tipi di dati più coerenti e minori costi di manutenzione.
Saeed Neamati,

1
@SaeedNeamati Potresti voler rileggere l'articolo dalla risposta di Mark (" Hai mai sentito ... facciamolo, ci preoccuperemo delle prestazioni più tardi? ... Lo sento sempre ... ") e gbn è qui . Penso che il ritorno a casa sia che qualsiasi scelta inefficiente mostrerà le sue strisce sulla scala giusta e l'intestino di OP non è sbagliato.
ruffin,

14

Non è solo l'archiviazione di tabelle che è una considerazione. Se si utilizzano gli indici in cui la colonna int fa parte di una chiave composta, si desidera naturalmente che le pagine dell'indice siano il più complete possibile, poiché il risultato delle voci dell'indice è il più piccolo possibile.

Mi sarei sicuramente aspettato di scoprire che esaminare le voci dell'indice nelle pagine BTREE sarebbe un po 'più veloce con tipi di dati più piccoli. Tuttavia, qualsiasi VARCHAR coinvolto nelle voci di indice compenserebbe (annullerebbe) i guadagni di prestazioni dall'uso di TINYINT su INT.

Ciononostante, se le voci di indice hanno voci composte e tutte sono numeri interi, più piccoli sono numeri interi a byte, migliore e più veloce.


13

Tutto diventa più complesso quando i database diventano più grandi:

  • le finestre di manutenzione devono essere ingrandite o riprogrammate
  • backup (il backup completo di fine giornata diventa un assurdo dispendio di tempo, quindi è necessario un backup differenziale o addirittura log e fare l'intero una volta alla settimana, forse una volta al mese)
  • le manutenzioni delle prestazioni diventano un dispendio di tempo (la creazione di un indice su una tabella multi-milione di righe non richiede poco tempo per l'esecuzione) e deve essere riprogrammata e peggiora se la tabella è ampia ...
  • E trasmettere quel backup da 100 Gb attraverso la rete non è ciò che chiamo un gioco da ragazzi - specialmente se la rete (per qualche ragione sconosciuta) è testarda a lasciare cadere la connessione sul segno da 75 Gb ... (è successo con un'installazione che stavo lavorando che stava eseguendo il backup su un'unità mappata sulla rete - rete) ...

E quali tipi di dati hanno a che fare con questo? QUALUNQUE COSA. L'uso di dimensioni di riga più grandi del necessario consente di riempire le pagine del database prima del necessario o addirittura di sprecare spazio se le dimensioni della riga sono tali che non è possibile registrare più di un record sulla pagina. Il risultato sono più pagine necessarie per la scrittura e la lettura, più memoria RAM viene utilizzata per memorizzare nella cache (i record più grandi richiedono memoria più grande). E poiché i tipi di dati sono specificati più grandi del necessario dal disco, gli indici subiranno lo stesso problema, specialmente se si raggruppa quella chiave primaria composita da 2 colonne BIGINT poiché qualsiasi altro indice creato copierà implicitamente quella chiave primaria nella loro definizione.

Se sai che alcune colonne in una tabella che avranno milioni di righe o addirittura una piccola tabella che verranno convertite in più milioni di righe che non richiedono un numero intero di 4 byte per memorizzare i loro dati, ma un 2 byte sarebbe basta - usa SMALLINT . Se i valori nell'intervallo 0-255 sono sufficienti, TINYINT . Una bandiera sì / no? C'è BIT .


9

Mentre per tinyintvs intci sono chiare differenze come spazio su disco, suddivisioni di pagina e tempi di manutenzione, non ci sarebbe nessuno di questi per varchar.

Quindi perché non dichiarare tutti i campi di testo come varchar(4000), poiché utilizzerà comunque solo lo spazio necessario? Ancora di più ti verrà garantito che i tuoi dati non verranno mai troncati.

La risposta è ovviamente:

  1. Chiarimento delle tue intenzioni (poiché nessuno capirà perché un campo nome dovrebbe contenere 4000 caratteri)
  2. Convalida come vuoi assicurarti che nessuno inserisca un'intera biografia come nome.

Questi stessi motivi si applicano tinyintanche a.


3
Questa è una discussione precedente, ma il chiarimento e la convalida non sono l'unica ragione. Se hai VARCHAR (4000) per qualcosa che dovrebbe essere VARCHAR (20), il piano di query penserà che i requisiti di memoria e CPU siano molti multipli di ciò che dovrebbero essere per quanto riguarda quella colonna. Non mi sono preso il tempo per farlo, ma suppongo che probabilmente lo puoi vedere guardando un piano di query per VARCHAR (20) e quindi passare a VARCHAR (4000) e controllare i costi stimati.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.