Mi rendo conto che CHAR è raccomandato se tutti i miei valori sono a larghezza fissa. Ma allora? Perché non selezionare VARCHAR per tutti i campi di testo solo per sicurezza.
Mi rendo conto che CHAR è raccomandato se tutti i miei valori sono a larghezza fissa. Ma allora? Perché non selezionare VARCHAR per tutti i campi di testo solo per sicurezza.
Risposte:
In genere, selezionare CHAR se tutte le righe avranno quasi la stessa lunghezza . Scegli VARCHAR quando la lunghezza varia in modo significativo. CHAR potrebbe anche essere un po 'più veloce perché tutte le righe hanno la stessa lunghezza.
Varia in base all'implementazione del DB, ma generalmente VARCHAR utilizza uno o due byte di memoria in più (per lunghezza o terminazione) oltre ai dati effettivi. Quindi (supponendo che tu stia utilizzando un set di caratteri a un byte) memorizzando la parola "FooBar"
La linea di fondo è che CHAR può essere più veloce e più efficiente in termini di spazio per i dati relativamente della stessa lunghezza (con una differenza di lunghezza di due caratteri).
Nota : Microsoft SQL ha 2 byte di sovraccarico per un VARCHAR. Questo può variare da DB a DB, ma generalmente è necessario almeno 1 byte di overhead per indicare la lunghezza o l'EOL su un VARCHAR.
Come sottolineato da Gaven nei commenti, se si utilizza un set di caratteri a byte variabile di lunghezza variabile come UTF8, CHAR memorizza il numero massimo di byte necessari per memorizzare il numero di caratteri. Quindi, se UTF8 necessita di un massimo di 3 byte per memorizzare un carattere, allora CHAR (6) sarà fissato a 18 byte, anche se si memorizzano solo caratteri latini1. Quindi in questo caso VARCHAR diventa una scelta molto migliore.
Se lavori con me e lavori con Oracle, probabilmente ti farei usare varchar
in quasi ogni circostanza. L'ipotesi che char
utilizza meno potenza di elaborazione di quanto varchar
possa essere vero ... per ora ... ma i motori di database migliorano nel tempo e questo tipo di regola generale ha la creazione di un "mito" futuro.
Un'altra cosa: non ho mai visto un problema di prestazioni perché qualcuno ha deciso di seguirlo varchar
. Utilizzerai molto meglio il tuo tempo scrivendo un buon codice (meno chiamate al database) e un efficiente SQL (come funzionano gli indici, come fa l'ottimizzatore a prendere decisioni, perché è exists
più veloce del in
solito ...).
Pensiero finale: ho visto tutti i tipi di problemi con l'uso di CHAR
, persone che cercano "" quando dovrebbero cercare "" o persone che cercano "FOO" quando dovrebbero cercare "FOO (spazi qui) o persone che non tagliano gli spazi vuoti finali o i bug con Powerbuilder che aggiunge fino a 2000 spazi al valore che restituisce da una procedura Oracle.
Oltre ai vantaggi in termini di prestazioni, è CHAR
possibile indicare che tutti i valori devono avere la stessa lunghezza, ad esempio una colonna per le abbreviazioni degli Stati Uniti.
CHAR
, dovrai assicurarti che il riempimento degli sconti del vincolo sia completo.
Char è un po 'più veloce, quindi se hai una colonna che SAPI avrà una certa lunghezza, usa char. Ad esempio, la memorizzazione (M) ale / (F) emale / (U) nota per genere o 2 caratteri per uno stato americano.
NChar o Char funzionano meglio delle loro alternative var?
Ottima domanda La semplice risposta è sì in determinate situazioni. Vediamo se questo può essere spiegato.
Ovviamente sappiamo tutti che se creo una tabella con una colonna di varchar (255) (chiamiamo questa colonna myColumn) e inserisco un milione di righe ma inserisco solo pochi caratteri in myColumn per ogni riga, la tabella sarà molto più piccola (nel complesso numero di pagine di dati necessarie al motore di archiviazione) rispetto a se avessi creato myColumn come char (255). Ogni volta che eseguo un'operazione (DML) su quella tabella e richiedo molte righe, sarà più veloce quando myColumn è varchar perché non devo spostare tutti quegli spazi "extra" alla fine. Sposta, come nel caso in cui SQL Server esegua ordinamenti interni, ad esempio durante un'operazione distinta o unione, o se sceglie un'unione durante il suo piano di query, ecc.
Ma c'è un certo sovraccarico nell'uso di varchar. SQL Server deve utilizzare un indicatore a due byte (sovraccarico) per, su ogni riga, sapere quanti byte ha il myColumn di quella particolare riga. Non sono i 2 byte extra che presentano il problema, è la necessità di "decodificare" la lunghezza dei dati in myColumn su ogni riga.
Nelle mie esperienze ha più senso usare char invece di varchar su colonne che verranno unite nelle query. Ad esempio la chiave primaria di una tabella o qualche altra colonna che verrà indicizzata. CustomerNumber su una tabella demografica, o CodeID su una tabella di decodifica, o forse OrderNumber su una tabella di ordini. Utilizzando char, il motore di query può eseguire più rapidamente l'unione perché può eseguire l'aritmetica del puntatore diritto (in modo deterministico) anziché dover spostare i puntatori di una quantità variabile di byte durante la lettura delle pagine. So che potrei averti perso in quest'ultima frase. I join in SQL Server si basano sull'idea di "predicati". Un predicato è una condizione. Ad esempio myColumn = 1 o OrderNumber <500.
Pertanto, se SQL Server sta eseguendo un'istruzione DML e i predicati o le "chiavi" su cui si uniscono hanno una lunghezza fissa (char), il motore di query non deve fare altrettanto lavoro per abbinare le righe da una tabella a quelle da un altro tavolo. Non dovrà scoprire per quanto tempo i dati sono nella riga e quindi scorrere la stringa per trovare la fine. Tutto ciò richiede tempo.
Ora tieni presente che questo può essere facilmente implementato male. Ho visto char usato per i campi chiave primari nei sistemi online. La larghezza deve essere ridotta, ovvero char (15) o qualcosa di ragionevole. E funziona meglio nei sistemi online perché di solito stai solo recuperando o eseguendo l'uperting di un piccolo numero di righe, quindi dover "ritirare" quegli spazi finali che otterrai nel set di risultati è un compito banale invece di dover unirti a milioni di righe da una tabella a milioni di righe su un'altra tabella.
Un altro motivo per cui CHAR ha senso su varchar sui sistemi online è che riduce le divisioni di pagina. Usando char, stai essenzialmente "riservando" (e sprecando) quello spazio, quindi se un utente arriva più tardi e inserisce più dati in quella colonna, SQL ha già allocato spazio per esso e in esso va.
Un altro motivo per usare CHAR è simile al secondo motivo. Se un programmatore o un utente esegue un aggiornamento "batch" a milioni di righe, ad esempio aggiungendo una frase a un campo di nota, nel mezzo della notte non riceverai una chiamata dal tuo DBA chiedendoti perché le sue unità sono piene. In altre parole, porta a una crescita più prevedibile delle dimensioni di un database.
Quindi questi sono 3 modi in cui un sistema online (OLTP) può beneficiare di char su varchar. Non uso quasi mai i caratteri in uno scenario di magazzino / analisi / OLAP perché di solito hai così tanti dati che tutte quelle colonne di caratteri possono aggiungere a un sacco di spazio sprecato.
Tieni presente che char può rendere il tuo database molto più grande, ma la maggior parte degli strumenti di backup ha una compressione dei dati, quindi i tuoi backup tendono ad avere le stesse dimensioni di se avessi usato varchar. Ad esempio LiteSpeed o RedGate SQL Backup.
Un altro uso è nelle viste create per esportare i dati in un file a larghezza fissa. Diciamo che devo esportare alcuni dati in un file flat per essere letto da un mainframe. È una larghezza fissa (non delimitata). Mi piace archiviare i dati nella mia tabella "staging" come varchar (consumando così meno spazio sul mio database) e quindi utilizzare una vista per CAST tutto al suo equivalente char, con la lunghezza corrispondente alla larghezza della larghezza fissa per quella colonna . Per esempio:
create table tblStagingTable (
pkID BIGINT (IDENTITY,1,1),
CustomerFirstName varchar(30),
CustomerLastName varchar(30),
CustomerCityStateZip varchar(100),
CustomerCurrentBalance money )
insert into tblStagingTable
(CustomerFirstName,CustomerLastName, CustomerCityStateZip) ('Joe','Blow','123 Main St Washington, MD 12345', 123.45)
create view vwStagingTable AS
SELECT CustomerFirstName = CAST(CustomerFirstName as CHAR(30)),
CustomerLastName = CAST(CustomerLastName as CHAR(30)),
CustomerCityStateZip = CAST(CustomerCityStateZip as CHAR(100)),
CustomerCurrentBalance = CAST(CAST(CustomerCurrentBalance as NUMERIC(9,2)) AS CHAR(10))
SELECT * from vwStagingTable
Questo è interessante perché internamente i miei dati occupano meno spazio perché utilizzano varchar. Ma quando uso DTS o SSIS o anche solo un copia e incolla da SSMS a Blocco note, posso usare la vista e ottenere il giusto numero di spazi finali. In DTS avevamo una funzione chiamata, accidenti dimentico che penso che si chiamasse "suggerisci colonne" o qualcosa del genere. In SSIS non puoi più farlo, devi definire noiosamente la gestione connessione file flat. Ma dal momento che hai impostato la vista, SSIS può conoscere la larghezza di ogni colonna e può risparmiare un sacco di tempo durante la creazione delle attività del flusso di dati.
Quindi, in conclusione ... usa varchar. Esistono un numero molto limitato di motivi per utilizzare char ed è solo per motivi di prestazioni. Se hai un sistema con centinaia di milioni di righe vedrai una notevole differenza se i predicati sono deterministici (char) ma per la maggior parte dei sistemi l'utilizzo di char sta semplicemente sprecando spazio.
Spero che aiuti. Jeff
Ci sono vantaggi in termini di prestazioni, ma eccone uno che non è stato menzionato: migrazione delle righe. Con char, riservi l'intero spazio in anticipo, quindi diciamo che hai un char (1000) e memorizzi 10 caratteri, utilizzerai tutti i 1000 caratteri di spazio. In varchar2 (1000), utilizzerai solo 10 caratteri. Il problema si presenta quando si modificano i dati. Supponiamo che tu aggiorni la colonna per contenere ora 900 caratteri. È possibile che lo spazio per espandere il varchar non sia disponibile nel blocco corrente. In tal caso, il motore DB deve migrare la riga su un altro blocco e creare un puntatore nel blocco originale sulla nuova riga nel nuovo blocco. Per leggere questi dati, il motore DB dovrà ora leggere 2 blocchi.
Nessuno può dire in modo equivoco che varchar o char sono migliori. C'è uno spazio per il trade-off temporale e si considera se i dati verranno aggiornati, specialmente se ci sono buone probabilità che crescano.
Esiste una differenza tra l'ottimizzazione precoce delle prestazioni e l'utilizzo di un tipo di regola di best practice. Se stai creando nuove tabelle in cui avrai sempre un campo di lunghezza fissa, ha senso usare CHAR, dovresti usarlo in quel caso. Questa non è un'ottimizzazione precoce, ma piuttosto l'implementazione di una regola empirica (o best practice).
vale a dire - Se si dispone di un campo di stato di 2 lettere, utilizzare CHAR (2). Se si dispone di un campo con i nomi di stato effettivi, utilizzare VARCHAR.
Sceglierei varchar a meno che la colonna non memorizzi un valore fisso come il codice di stato USA - che è sempre lungo 2 caratteri e l'elenco del codice di stati USA valido non cambia spesso :).
In ogni altro caso, anche come memorizzare la password con hash (che è di lunghezza fissa), sceglierei varchar.
Perché - la colonna del tipo di carattere viene sempre soddisfatta con spazi, il che rende la colonna my_column definita come char (5) con valore 'ABC' all'interno del confronto:
my_column = 'ABC' -- my_column stores 'ABC ' value which is different then 'ABC'
falsa.
Questa funzione potrebbe portare a molti bug irritanti durante lo sviluppo e rendere più difficili i test.
CHAR occupa meno spazio di archiviazione rispetto a VARCHAR se tutti i valori dei dati in quel campo hanno la stessa lunghezza. Ora forse nel 2009 un database da 800 GB è lo stesso a tutti gli effetti di un 810 GB se hai convertito i VARCHAR in CHAR, ma per stringhe brevi (1 o 2 caratteri), CHAR è ancora una "best practice" del settore, direi.
Ora, se si guarda alla grande varietà di tipi di dati che la maggior parte dei database fornisce anche solo per i numeri interi (bit, tiny, int, bigint), ci sono ragioni per scegliere l'una rispetto all'altra. Scegliere semplicemente bigint ogni volta è in realtà un po 'ignorante degli scopi e degli usi del campo. Se un campo rappresenta semplicemente l'età di una persona in anni, un bigint è eccessivo. Ora non è necessariamente "sbagliato", ma non è efficiente.
Ma è un argomento interessante, e poiché i database migliorano nel tempo, si potrebbe sostenere che CHAR vs VARCHAR diventa meno rilevante.
Attendo il commento di Jim McKeeth.
Inoltre, l'indicizzazione e le scansioni di tabelle complete sono più veloci se la tabella ha solo colonne CHAR. Fondamentalmente l'ottimizzatore sarà in grado di prevedere quanto è grande ogni record se ha solo colonne CHAR, mentre deve controllare il valore della dimensione di ogni colonna VARCHAR.
Inoltre, se aggiorni una colonna VARCHAR a una dimensione superiore al suo contenuto precedente, potresti forzare il database a ricostruire i suoi indici (perché hai costretto il database a spostare fisicamente il record su disco). Mentre con le colonne CHAR non succederà mai.
Ma probabilmente non ti interesserà il successo delle prestazioni a meno che il tuo tavolo non sia enorme.
Ricorda le sagge parole di Djikstra. L'ottimizzazione precoce delle prestazioni è la radice di tutti i mali.
CHAR
colonna, anche gli indici devono essere aggiornati. Non vi è alcuna differenza nell'aggiornamento di una colonna VARCHAR o CHAR al riguardo. Pensa ad aggiornare FOO
a BAR
.
Molte persone hanno sottolineato che se si conosce la lunghezza esatta del valore utilizzando CHAR ha alcuni vantaggi. Ma mentre conservare gli Stati Uniti come CHAR (2) è fantastico oggi, quando ricevi il messaggio dalle vendite che "Abbiamo appena fatto la nostra prima vendita in Australia", sei in un mondo di dolore. Mando sempre a sopravvalutare il tempo in cui penso che i campi dovranno essere piuttosto che fare un'ipotesi 'esatta' da coprire per eventi futuri. VARCHAR mi darà maggiore flessibilità in questo settore.
Penso che nel tuo caso probabilmente non vi sia motivo di non scegliere Varchar. Ti dà flessibilità e come è stato detto da un numero di intervistati, le prestazioni sono tali ora che, tranne in circostanze molto specifiche, noi mortali (al contrario dei DBA di Google) non noteremo la differenza.
Una cosa interessante da notare quando si tratta di Tipi DB è che sqlite (un mini database popolare con prestazioni piuttosto impressionanti) mette tutto nel database come una stringa e tipi al volo.
Uso sempre VarChar e di solito lo rendo molto più grande di quello di cui potrei aver bisogno. Per esempio. 50 per Firstname, come dici tu, perché non solo per essere al sicuro.
Non userei MAI i caratteri. Ho avuto questo dibattito con molte persone e hanno sempre sollevato il cliché stanco che il carbone è più veloce. Bene dico, quanto più veloce? Di cosa stiamo parlando qui, millisecondi, secondi e, in caso affermativo, quanti? Mi stai dicendo perché qualcuno afferma che è pochi millisecondi più veloce, dovremmo introdurre tonnellate di bug difficili da correggere nel sistema?
Quindi, ecco alcuni problemi che incontrerai:
Ogni campo sarà riempito, quindi finirai con il codice per sempre che ha RTRIMS ovunque. Questo è anche un enorme spreco di spazio su disco per i campi più lunghi.
Ora supponiamo che tu abbia l'esempio per antonomasia di un campo carattere di un solo carattere ma il campo è facoltativo. Se qualcuno passa una stringa vuota a quel campo, diventa uno spazio. Quindi, quando un'altra applicazione / processo lo interroga, ottengono uno spazio singolo, se non usano rtrim. Abbiamo avuto documenti xml, file e altri programmi, visualizzare solo uno spazio, in campi opzionali e rompere le cose.
Quindi ora devi assicurarti di passare null e non stringa vuota al campo char. Ma NON è l'uso corretto di null. Ecco l'uso di null. Supponiamo che tu ottenga un file da un fornitore
Nome | Genere | Città
Bob || Los Angeles
Se il genere non è specificato di quello che inserisci Bob, svuota stringa e Los Angeles nella tabella. Ora supponiamo che tu ottenga il file e che il suo formato cambi e il genere non sia più incluso ma era in passato.
Nome | Città
Bob | Seattle
Bene, dato che il genere non è incluso, userei null. Varchars supporta questo senza problemi.
Il carattere invece è diverso. Devi sempre inviare null. Se invii mai una stringa vuota, finirai con un campo che contiene degli spazi.
Potrei andare avanti all'infinito con tutti i bug che ho dovuto correggere dai caratteri e in circa 20 anni di sviluppo.
C'è un piccolo overhead di elaborazione nel calcolo delle dimensioni effettive necessarie per un valore di colonna e nell'allocazione dello spazio per un Varchar, quindi se sei sicuramente sicuro di quanto tempo sarà sempre il valore, è meglio usare Char ed evitare l'hit.
È il classico compromesso tra spazio e prestazioni.
In MS SQL 2005, Varchar (o NVarchar per lanuagues che richiedono due byte per carattere, ovvero cinese) sono di lunghezza variabile. Se si aggiunge alla riga dopo che è stata scritta sul disco rigido, i dati verranno localizzati in una posizione non contigua alla riga originale e si tradurrà in una frammentazione dei file di dati. Ciò influirà sulle prestazioni.
Quindi, se lo spazio non è un problema, Char è migliore per le prestazioni, ma se si desidera mantenere ridotte le dimensioni del database, varchars è migliore.
La frammentazione. Char riserva spazio e VarChar no. La suddivisione della pagina può essere richiesta per consentire l'aggiornamento a varchar.
CHAR
colonna.
In alcuni database SQL, VARCHAR sarà riempito fino alla sua dimensione massima al fine di ottimizzare gli offset, questo per velocizzare scansioni e indici di tabelle complete.
Per questo motivo, non si ha alcun risparmio di spazio utilizzando un VARCHAR (200) rispetto a un CHAR (200)
L'uso di CHAR (NCHAR) e VARCHAR (NVARCHAR) comporta differenze nel modo in cui il server di database memorizza i dati. Il primo introduce spazi vuoti finali; Ho riscontrato un problema durante l'utilizzo con l'operatore LIKE nelle funzioni SQL SERVER. Quindi devo renderlo sicuro usando VARCHAR (NVARCHAR) tutte le volte.
Ad esempio, se abbiamo una tabella TEST (ID INT, Status CHAR (1)) e scrivi una funzione per elencare tutti i record con un valore specifico come il seguente:
CREATE FUNCTION List(@Status AS CHAR(1) = '')
RETURNS TABLE
AS
RETURN
SELECT * FROM TEST
WHERE Status LIKE '%' + @Status '%'
In questa funzione ci aspettiamo che quando mettiamo il parametro predefinito la funzione restituirà tutte le righe, ma in realtà non lo fa. Modificare il tipo di dati @Status in VARCHAR risolverà il problema.