c'è un vantaggio per varchar (500) rispetto a varchar (8000)?


90

Ho letto su questo nei forum MSDN e qui e non sono ancora chiaro. Penso che sia corretto: Varchar (max) verrà memorizzato come un tipo di dati di testo, quindi ha degli svantaggi. Quindi diciamo che il tuo campo sarà attendibilmente inferiore a 8000 caratteri. Come un campo BusinessName nella tabella del database. In realtà, il nome di un'attività sarà probabilmente sempre sotto (tirando fuori un numero dal mio cappello) 500 caratteri. Sembra che molti campi varchar che ho incontrato rientrino ben al di sotto del numero di caratteri 8k.

Quindi dovrei rendere quel campo un varchar (500) invece di varchar (8000)? Da quello che ho capito di SQL non c'è differenza tra questi due. Quindi, per semplificare la vita, vorrei definire tutti i miei campi varchar come varchar (8000). Questo ha degli svantaggi?

Correlato: dimensione delle colonne varchar (non mi sentivo come se questo avesse risposto alla mia domanda).


6
Immagina di provare a inserire un nome commerciale lungo 500 caratteri su un biglietto da visita ... :)
OMG Ponies

2
@OMG Ponies: ogni volta che vedo il tuo nome utente ridacchiò. Allora, cosa stavi dicendo? (
Sto

4
@jcollum: SpaceMan Spiff otterrà sempre il mio voto. Non è vero: qualsiasi Calvin & Hobbes andrà bene, ma soprattutto quelli che scolpiscono la neve. O il tiranosauro che vola su un F-14. Ma sto divagando ...
OMG Ponies

Risposte:


20

Dal punto di vista dell'elaborazione, non farà differenza usare varchar (8000) vs varchar (500). È più un tipo di "buona pratica" definire una lunghezza massima che un campo dovrebbe contenere e rendere il tuo varchar quella lunghezza. È qualcosa che può essere utilizzato per assistere con la convalida dei dati. Ad esempio, fare un'abbreviazione di stato di 2 caratteri o un codice postale / CAP di 5 o 9 caratteri. Questa era una distinzione più importante quando i tuoi dati interagivano con altri sistemi o interfacce utente in cui la lunghezza del campo era critica (ad esempio un set di dati di file flat mainframe), ma al giorno d'oggi penso che sia più un'abitudine che altro.


3
Ha senso ... per cose che hanno naturalmente una lunghezza massima. Ma cosa fai quando la lunghezza massima non è evidente? Ad esempio il nome di un'attività commerciale.
jcollum

2
Per qualcosa del genere, se non prevedo alcun modo per prevedere quale potrebbe essere la dimensione, di solito vado con un varchar (8000) o varchar (max), a seconda del tipo di dati
BBlake

4
Sembra che questo faccia la differenza in termini di prestazioni, anche nel 2017: dba.stackexchange.com/a/162117/1822
a_horse_with_no_name

1
Risposte più recenti mostrano che ci sono dei costi: influisce sulla logica di ottimizzazione della risposta di Martin Smith e considera anche i problemi di dimensione delle righe totali di 8K menzionati da gbn e Oliver .
ToolmakerSteve

124

Un esempio in cui questo può fare la differenza è che può impedire un'ottimizzazione delle prestazioni che evita di aggiungere informazioni sul controllo delle versioni delle righe alle tabelle con trigger after.

Questo è coperto da SQL Kiwi qui

La dimensione effettiva dei dati archiviati è irrilevante: è la dimensione potenziale che conta.

Allo stesso modo se si utilizzano tabelle ottimizzate per la memoria dal 2016 è stato possibile utilizzare colonne LOB o combinazioni di larghezze di colonna che potrebbero potenzialmente superare il limite di inrow ma con una penalità.

Le colonne (Max) vengono sempre memorizzate fuori riga. Per altre colonne, se la dimensione della riga di dati nella definizione della tabella può superare i 8.060 byte, SQL Server inserisce le colonne di lunghezza variabile più grandi fuori riga. Ancora una volta, non dipende dalla quantità di dati archiviati lì.

Ciò può avere un grande effetto negativo sul consumo di memoria e sulle prestazioni

Un altro caso in cui dichiarare eccessivamente le larghezze delle colonne può fare una grande differenza è se la tabella verrà mai elaborata utilizzando SSIS. La memoria allocata per le colonne a lunghezza variabile (non BLOB) è fissa per ogni riga in un albero di esecuzione ed è in base alla lunghezza massima dichiarata delle colonne, il che può portare a un utilizzo inefficiente dei buffer di memoria (esempio) . Sebbene lo sviluppatore del pacchetto SSIS possa dichiarare una dimensione della colonna inferiore rispetto alla fonte, questa analisi è meglio eseguire in anticipo e applicare lì.

Torna nel motore di SQL Server stesso un caso simile è che quando si calcola la concessione di memoria da allocare per le SORToperazioni, SQL Server presuppone che le varchar(x)colonne consumeranno in media x/2byte.

Se la maggior parte delle tue varcharcolonne è più piena di quella, ciò può portare alla sortfuoriuscita delle operazioni tempdb.

Nel tuo caso, se le tue varcharcolonne sono dichiarate come 8000byte ma in realtà hanno un contenuto molto inferiore a quello, alla tua query verrà allocata memoria che non richiede, il che è ovviamente inefficiente e può portare ad attese per concessioni di memoria.

Questo argomento è trattato nella Parte 2 del Webcast 1 dei workshop SQL scaricabile da qui o vedi sotto.

use tempdb;

CREATE TABLE T(
id INT IDENTITY(1,1) PRIMARY KEY,
number int,
name8000 VARCHAR(8000),
name500 VARCHAR(500))

INSERT INTO  T 
(number,name8000,name500)
SELECT number, name, name /*<--Same contents in both cols*/
FROM master..spt_values

SELECT id,name500
FROM T
ORDER BY number

Immagine dello schermo

SELECT id,name8000
FROM T
ORDER BY number

Immagine dello schermo


1
quindi, se quasi tutti i miei valori sono 3 o 4 caratteri, non possono mai superare i 4 caratteri, e voglio evitare "operazioni di ordinamento che si riversano in tempdb", dichiarerò la mia colonna VARCHAR (8) e userò un vincolo CHECK per applicare quella colonna la larghezza non può superare i 4 caratteri. Cosa ne pensi?
AK

12
@AlexKuznetsov - Per quella situazione li dichiarerei char(4)poiché ci sono comunque 2 byte di overhead per colonna variabile.
Martin Smith,

9

Oltre alle migliori pratiche (risposta di BBlake)

  • Ricevi avvisi sulla dimensione massima delle righe (8060) byte e sulla larghezza dell'indice (900 byte) con DDL
  • DML morirà se superi questi limiti
  • ANSI PADDING ON è l'impostazione predefinita, quindi potresti finire per memorizzare un intero carico di spazi bianchi

38
Giusto per chiarire su ANSI PADDING ON: quando si usano i tipi nvarchare varchar, questo significa solo che gli spazi finali vengono conservati dopo l'inserimento - non che i valori siano riempiti con spazi alla dimensione della colonna, come in chare nchar.
Ben M

9

Ci sono alcuni svantaggi delle colonne di grandi dimensioni che sono un po 'meno evidenti e potrebbero catturarti un po' più tardi:

  • Tutte le colonne che utilizzi in un INDICE non devono superare i 900 byte
  • Tutte le colonne in una clausola ORDER BY non possono superare 8060 byte. Questo è un po 'difficile da capire poiché si applica solo ad alcune colonne. Vedere Limite di dimensione riga SQL 2008 R2 superato per i dettagli)
  • Se la dimensione totale della riga supera 8060 byte, si ottiene una " fuoriuscita di pagina " per quella riga. Ciò potrebbe influire sulle prestazioni (una pagina è un'unità di allocazione in SQL Server ed è fissata a 8000 byte + un po 'di overhead. Il superamento di questo non sarà grave, ma è evidente e dovresti cercare di evitarlo se puoi facilmente)
  • Molte altre strutture di dati interne, buffer e, non ultime, le tue variabili e variabili di tabella devono tutte rispecchiare queste dimensioni. Con dimensioni eccessive, un'allocazione di memoria eccessiva può influire sulle prestazioni

Come regola generale, cerca di essere prudente con la larghezza della colonna. Se diventa un problema, puoi facilmente espanderlo per adattarlo alle esigenze. Se in seguito noti problemi di memoria, ridurre in seguito un'ampia colonna potrebbe diventare impossibile senza perdere dati e non saprai da dove iniziare.

Nel tuo esempio dei nomi delle attività commerciali, pensa a dove puoi visualizzarli. C'è davvero spazio per 500 caratteri ?? In caso contrario, non ha molto senso conservarli come tali. http://en.wikipedia.org/wiki/List_of_compamins_of_the_United_States elenca alcuni nomi di società e il massimo è di circa 50 caratteri. Quindi userei 100 per la colonna max. Forse più come 80.


2

Idealmente vorresti andare più piccolo di quello, fino a una lunghezza di dimensioni ragionevoli (500 non è di dimensioni ragionevoli) e assicurarti che la convalida del client rilevi quando i dati saranno troppo grandi e invierà un errore utile.

Sebbene il varchar non riserverà effettivamente spazio nel database per lo spazio inutilizzato, ricordo che le versioni di SQL Server hanno una piccola curiosità sulle righe del database che sono più larghe di un certo numero di byte (non ricordo il conteggio esatto) e in realtà vengono eliminate qualunque dato non rientrava. Un certo numero di quei byte era riservato per cose interne a SQL Server.


vero, anche questa era una preoccupazione molto più grande. Ma oggigiorno lo spazio costa davvero poco, quindi non credo sia una grande preoccupazione da prendere in considerazione, almeno dal mio punto di vista.
BBlake

1
@jcollum: Nel tuo esempio, 500 non sembra abbastanza dimensionato per un nome commerciale.
Otis

1
@BBlake: indipendentemente dal costo di archiviazione, se SQL Server ha ancora limiti di dimensione delle righe, non importa quanto spazio di archiviazione hai. È possibile archiviare tutto in textblob, ma ci sono alcune operazioni SQL che non è possibile eseguire su un blob che è possibile eseguire su un varchar.
Otis

2
@Otis: il punto è questo: non ci sono vincoli effettivi sulle dimensioni di un nome commerciale. A meno che non ci sia una legge da qualche parte. Quindi in quel caso creerei quel campo varchar (8000) e lo chiamerei un giorno. Il mio pensiero è questo: vincolo reale? varchar (x). Nessun vero vincolo? varchar (8000).
jcollum

24
Pensavo che circa 30 caratteri fossero buoni per i nomi delle città, finché non ho visto El Pueblo de Nuestra Señora la Reina de los Ángeles del Río de Porciúncula
StuartLC
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.