Esito ad aggiungere ancora un'altra risposta qui, poiché ce ne sono già alcune, ma alcuni punti devono essere fatti o non sono stati fatti o non sono stati fatti chiaramente.
Primo: Do non usare sempre NVARCHAR
. Questo è un atteggiamento / approccio molto pericoloso e spesso costoso. E non è meglio dire " Non usare mai i cursori" poiché a volte sono il mezzo più efficace per risolvere un problema particolare e il modo più comune per fare un WHILE
ciclo sarà quasi sempre più lento di un cursore fatto correttamente .
L'unica volta che dovresti usare il termine "sempre" è quando consigli di "fare sempre ciò che è meglio per la situazione". È scontato che spesso sia difficile da determinare, specialmente quando si cerca di bilanciare i guadagni a breve termine nei tempi di sviluppo (manager: "abbiamo bisogno di questa funzione - di cui non si conosceva fino a ora - una settimana fa!") Con molto costi di manutenzione a medio termine (manager che inizialmente ha fatto pressione sul team per completare un progetto di 3 mesi in uno sprint di 3 settimane: "perché stiamo riscontrando questi problemi di prestazioni? Come avremmo potuto fare X che non ha flessibilità? Non possiamo permetterci uno sprint o due per risolvere questo problema. Cosa possiamo fare in una settimana in modo da poter tornare ai nostri elementi prioritari? E dobbiamo sicuramente dedicare più tempo alla progettazione in modo che ciò non accada! ").
Secondo: la risposta di @ gbn tocca alcuni punti molto importanti da considerare quando si prendono determinate decisioni sulla modellazione dei dati quando il percorso non è chiaro al 100%. Ma c'è ancora di più da considerare:
- dimensione dei file di registro delle transazioni
- tempo impiegato per replicare (se si utilizza la replica)
- tempo impiegato per ETL (se ETLing)
- tempo impiegato per spedire i log in un sistema remoto e ripristinarlo (se si utilizza Log Shipping)
- dimensione dei backup
- il tempo necessario per completare il backup
- il tempo necessario per eseguire un ripristino (questo potrebbe essere importante un giorno ;-)
- dimensione necessaria per tempdb
- esecuzione dei trigger (per tabelle inserite ed eliminate archiviate in tempdb)
- prestazioni del controllo delle versioni delle righe (se si utilizza ISOLAMENTO SNAPSHOT, poiché l'archivio versioni è in tempdb)
- capacità di ottenere nuovo spazio su disco quando il CFO afferma di aver appena speso $ 1 milione in una SAN l'anno scorso e quindi non autorizzerà altri $ 250k per spazio di archiviazione aggiuntivo
- il tempo necessario per eseguire le operazioni INSERT e UPDATE
- il tempo necessario per eseguire la manutenzione dell'indice
- ecc, ecc, ecc.
Sprecare spazio ha un enorme effetto a cascata su tutto il sistema. Ho scritto un articolo andando in dettaglio esplicito su questo argomento: Disk Is Cheap! ORLY? (è richiesta la registrazione gratuita; mi dispiace non controllo tale politica).
Terzo: mentre alcune risposte si incentrano erroneamente sull'aspetto "questa è una piccola app" e alcune suggeriscono correttamente di "utilizzare ciò che è appropriato", nessuna delle risposte ha fornito una vera guida all'OP Un dettaglio importante menzionato nella domanda è che questa è una pagina web per la loro scuola. Grande! Quindi possiamo suggerire che:
- I campi per i nomi degli studenti e / o delle facoltà dovrebbero essere probabilmente
NVARCHAR
poiché, nel tempo, sta diventando sempre più probabile che i nomi di altre culture vengano visualizzati in quei luoghi.
- Ma per indirizzo e nomi di città? Lo scopo dell'app non è stato dichiarato (sarebbe stato utile) ma supponendo che gli eventuali record di indirizzi riguardino solo una determinata regione geografica (ovvero una singola lingua / cultura), quindi utilizzare
VARCHAR
con l'apposita pagina di codice (che è determinato dalla Raccolta del campo).
- Se si memorizzano codici ISO di stato e / o paese (non è necessario archiviare
INT
/ TINYINT
poiché i codici ISO sono di lunghezza fissa, leggibili dall'uomo e bene, standard :) utilizzare CHAR(2)
per codici a due lettere e CHAR(3)
se si utilizzano codici a 3 lettere. E considera l'utilizzo di una raccolta binaria come Latin1_General_100_BIN2
.
- Se si memorizzano codici postali (ad esempio codici postali), utilizzare
VARCHAR
poiché è uno standard internazionale per non utilizzare mai lettere esterne all'AZ. E sì, usi ancora VARCHAR
anche se memorizzi solo i codici postali statunitensi e non INT poiché i codici postali non sono numeri, sono stringhe e alcuni di essi hanno uno "0" iniziale. E considera l'utilizzo di una raccolta binaria come Latin1_General_100_BIN2
.
- Se si memorizzano indirizzi e-mail e / o URL, utilizzare
NVARCHAR
poiché entrambi possono ora contenere caratteri Unicode.
- e così via....
Quarto: ora che hai i NVARCHAR
dati che occupano il doppio dello spazio necessario per i dati che si adattano perfettamente VARCHAR
("si adatta bene" = non si trasforma in "?") E in qualche modo, come per magia, l'applicazione è cresciuta e ora ci sono milioni di record in almeno uno di questi campi in cui la maggior parte delle righe sono ASCII standard ma alcune contengono caratteri Unicode quindi è necessario conservare NVARCHAR
, considerare quanto segue:
Se si utilizza SQL Server 2008-2016 RTM e si utilizza Enterprise Edition, oppure se si utilizza SQL Server 2016 SP1 (che ha reso disponibile la compressione dei dati in tutte le edizioni) o più recente, è possibile abilitare la compressione dei dati . La compressione dei dati può (ma non "sempre") comprimere i dati NCHAR
e i NVARCHAR
campi Unicode . I fattori determinanti sono:
NCHAR(1 - 4000)
e NVARCHAR(1 - 4000)
utilizzare lo schema di compressione standard per Unicode , ma solo a partire da SQL Server 2008 R2, E solo per i dati IN ROW, non OVERFLOW! Questo sembra essere migliore del normale algoritmo di compressione ROW / PAGE.
NVARCHAR(MAX)
e XML
(e immagino anche VARBINARY(MAX)
, TEXT
e NTEXT
) i dati IN ROW (non fuori riga nelle pagine LOB o OVERFLOW) possono almeno essere compressi PAGE, ma non ROW compressi. Naturalmente, la compressione PAGE dipende dalla dimensione del valore in-row: ho testato con VARCHAR (MAX) e ho visto che 6000 righe di caratteri / byte non si comprimerebbero, ma 4000 righe di caratteri / byte sì.
- Qualsiasi dato OFF ROW, LOB o OVERLOW = Nessuna compressione per te!
Se si utilizza SQL Server 2005 o 2008-2016 RTM e non su Enterprise Edition, è possibile avere due campi: uno VARCHAR
e uno NVARCHAR
. Ad esempio, supponiamo che tu stia memorizzando URL che sono principalmente tutti caratteri ASCII di base (valori 0 - 127) e quindi adatti VARCHAR
, ma a volte hanno caratteri Unicode. Lo schema può includere i seguenti 3 campi:
...
URLa VARCHAR(2048) NULL,
URLu NVARCHAR(2048) NULL,
URL AS (ISNULL(CONVERT(NVARCHAR([URLa])), [URLu])),
CONSTRAINT [CK_TableName_OneUrlMax] CHECK (
([URLa] IS NOT NULL OR [URLu] IS NOT NULL)
AND ([URLa] IS NULL OR [URLu] IS NULL))
);
In questo modello SCEGLI solo dalla [URL]
colonna calcolata. Per l'inserimento e l'aggiornamento, si determina quale campo utilizzare visualizzando se la conversione modifica il valore in ingresso, che deve essere di NVARCHAR
tipo:
INSERT INTO TableName (..., URLa, URLu)
VALUES (...,
IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
);
È possibile GZIP in entrata valori VARBINARY(MAX)
e quindi decomprimere in uscita:
- Per SQL Server 2005-2014: è possibile utilizzare SQLCLR. SQL # (una libreria SQLCLR che ho scritto) viene fornito con Util_GZip e Util_GUnzip nella versione gratuita
- Per SQL Server 2016 e versioni successive: è possibile utilizzare il built-in
COMPRESS
e le DECOMPRESS
funzioni, che sono anche GZip.
Se si utilizza SQL Server 2017 o versioni successive, è possibile cercare di rendere la tabella un indice Columnstore cluster.
Sebbene questa non sia ancora un'opzione praticabile, SQL Server 2019 introduce il supporto nativo per UTF-8 in VARCHAR
/ CHAR
datatypes. Al momento ci sono troppi bug per usarlo, ma se sono stati corretti, questa è un'opzione per alcuni scenari. Si prega di consultare il mio post " Supporto nativo UTF-8 in SQL Server 2019: Salvatore o Falso profeta? ", Per un'analisi dettagliata di questa nuova funzionalità.