sql-server - tipos - varchar max length sql server
¿Cuáles son las principales diferencias de rendimiento entre los tipos de datos varchar y nvarchar de SQL Server? (14)
Estoy trabajando en una base de datos para una aplicación web pequeña en mi escuela utilizando SQL Server 2005
.
Veo un par de escuelas de pensamiento sobre el tema de varchar
vs nvarchar
:
- Use
varchar
menos que trate con una gran cantidad de datos internacionalizados, luego usenvarchar
. - Solo usa
nvarchar
para todo.
Estoy empezando a ver los méritos de la vista 2. Sé que nvarchar ocupa el doble de espacio, pero eso no es necesariamente un gran problema ya que solo almacenará datos para unos pocos cientos de estudiantes. Para mí, parece que sería más fácil no preocuparse por eso y simplemente permitir que todo use nvarchar. ¿O hay algo que me falta?
¡Se consistente! Unirse a un VARCHAR para NVARCHAR tiene un gran éxito de rendimiento.
¿Por qué, en toda esta discusión, no se ha mencionado el UTF-8? El hecho de poder almacenar el intervalo completo de caracteres de Unicode no significa que uno tenga que asignar siempre dos bytes por carácter (o "punto de código" para usar el término UNICODE). Todo el ASCII es UTF-8. ¿SQL Server comprueba los campos VARCHAR () que el texto es ASCII estricto (es decir, bit cero superior de byte)? Espero que no.
Si luego desea almacenar Unicode y desea compatibilidad con aplicaciones antiguas solo ASCII, creo que usar VARCHAR () y UTF-8 sería la solución mágica: solo usa más espacio cuando lo necesita.
Para aquellos que no estén familiarizados con UTF-8, les recomiendo un manual .
Debido a que su aplicación es pequeña, esencialmente no hay un aumento considerable en el costo de usar nvarchar sobre varchar, y puede ahorrarse posibles dolores de cabeza en el futuro si tiene la necesidad de almacenar datos Unicode.
Dudo en agregar otra respuesta aquí ya que ya hay bastantes, pero es necesario hacer algunos puntos que no se han hecho o no se han hecho claramente.
Primero: No siempre use NVARCHAR
. Esa es una actitud / enfoque muy peligroso, y con frecuencia costoso. Y no es mejor decir " Nunca use cursores", ya que a veces son el medio más eficaz para resolver un problema en particular, y la solución común de hacer un bucle WHILE
casi siempre será más lenta que un cursor correctamente hecho.
La única vez que debe usar el término "siempre" es cuando se aconseja "hacer siempre lo mejor para la situación". Por supuesto, a menudo es difícil de determinar, especialmente cuando se trata de equilibrar las ganancias a corto plazo en el tiempo de desarrollo (administrador: "necesitamos esta función, que no conocía hasta hace poco, ¡hace una semana!") Con mucho tiempo. costos de mantenimiento a largo plazo (gerente que inicialmente presionó al equipo para completar un proyecto de 3 meses en un sprint de 3 semanas: "¿por qué tenemos estos problemas de rendimiento? ¿Cómo podríamos haber hecho X que no tiene flexibilidad? No podemos permitirnos un sprint o dos para solucionar este problema. ¿Qué podemos hacer en una semana para que podamos volver a nuestros elementos prioritarios? Y definitivamente necesitamos dedicar más tiempo al diseño para que esto no siga ocurriendo ".
Segundo: la respuesta de @gbn toca algunos puntos muy importantes a considerar cuando se toman ciertas decisiones de modelado de datos cuando la ruta no está clara al 100%. Pero hay aún más para considerar:
- tamaño de los archivos de registro de transacciones
- el tiempo que tarda en replicarse (si se usa la replicación)
- tiempo que lleva ETL (si ETLing)
- el tiempo que lleva enviar los registros a un sistema remoto y restaurarlos (si se usa el envío de registros)
- tamaño de las copias de seguridad
- El tiempo que lleva completar la copia de seguridad.
- el tiempo que lleva hacer una restauración (esto podría ser importante algún día ;-)
- tamaño necesario para tempdb
- rendimiento de los activadores (para las tablas insertadas y eliminadas que se almacenan en tempdb)
- rendimiento del control de versiones de filas (si se utiliza SNAPSHOT ISOLATION, ya que el almacén de versiones está en tempdb)
- la capacidad de obtener nuevo espacio en el disco cuando el CFO dice que solo gastaron $ 1 millón en una SAN el año pasado, por lo que no autorizarán otros $ 250k para almacenamiento adicional
- el tiempo que lleva realizar las operaciones de INSERTAR y ACTUALIZAR
- El tiempo que lleva hacer el mantenimiento del índice.
- etc, etc, etc.
El desperdicio de espacio tiene un enorme efecto de cascada en todo el sistema. Escribí un artículo con detalles explícitos sobre este tema: ¡El disco es barato! ORLY? (Se requiere inscripción gratuita; lo siento, no controlo esa política).
Tercero: si bien algunas respuestas se enfocan incorrectamente en el aspecto "esta es una aplicación pequeña", y algunas sugieren correctamente "usar lo que sea apropiado", ninguna de las respuestas proporcionó una guía real para el OP. Un detalle importante mencionado en la pregunta Es que esta es una página web para su escuela. ¡Genial! Así que podemos sugerir que:
- Los campos para los nombres de estudiantes y / o profesores probablemente deberían ser
NVARCHAR
ya que, con el tiempo, es cada vez más probable que los nombres de otras culturas se muestren en esos lugares. - ¿Pero para los nombres de calles y ciudades? El propósito de la aplicación no se indicó (hubiera sido útil), pero suponiendo que los registros de direcciones, en su caso, se refieran solo a una región geográfica particular (es decir, a un solo idioma / cultura), entonces use
VARCHAR
con la página de códigos correspondiente ( que se determina a partir de la Collación del campo). - Si almacena códigos ISO estatales y / o nacionales (no es necesario almacenar
INT
/TINYINT
ya que los códigos ISO son de longitud fija, legibles para las personas y estándar, estándar :) useCHAR(2)
para los códigos de dos letras yCHAR(3)
si usa 3 códigos de letras. Y considere usar unaLatin1_General_100_BIN2
binaria comoLatin1_General_100_BIN2
. - Si almacena códigos postales (es decir, códigos postales), use
VARCHAR
ya que es un estándar internacional que nunca use ninguna letra fuera de AZ. Y sí, aún useVARCHAR
aunque solo almacene códigos postales de EE. UU. Y no INT porque los códigos postales no son números, son cadenas, y algunos de ellos tienen un "0" inicial. Y considere usar unaLatin1_General_100_BIN2
binaria comoLatin1_General_100_BIN2
. - Si almacena direcciones de correo electrónico y / o URL, use
NVARCHAR
ya que ambos pueden contener caracteres Unicode. - y así....
Cuarto: Ahora que tiene datos NVARCHAR
que ocupan el doble de espacio del necesario para los datos que encajan bien en VARCHAR
("se ajusta bien" = no se convierte en "?") Y de alguna manera, como por arte de magia, la aplicación creció y ahora hay millones de registros en al menos uno de estos campos donde la mayoría de las filas son ASCII estándar pero algunos contienen caracteres Unicode, por lo que debe mantener NVARCHAR
, considere lo siguiente:
Si está utilizando SQL Server 2008 - 2016 RTM y está en Enterprise Edition, O si usa SQL Server 2016 SP1 (que hizo que la compresión de datos esté disponible en todas las ediciones) o más reciente, puede habilitar la compresión de datos . La compresión de datos puede (pero no "siempre") comprimir datos Unicode en los campos
NCHAR
yNVARCHAR
. Los factores determinantes son:-
NCHAR(1 - 4000)
yNVARCHAR(1 - 4000)
usan el Esquema de compresión estándar para Unicode , pero solo se inicia en SQL Server 2008 R2, Y solo para datos IN ROW, ¡no en OVERFLOW! Esto parece ser mejor que el algoritmo de compresión ROW / PAGE regular. -
NVARCHAR(MAX)
yXML
(y supongo que tambiénVARBINARY(MAX)
,TEXT
yNTEXT
) que están EN ROW (no fuera de la fila en páginas LOB o OVERFLOW) pueden al menos comprimirse en PAGE, pero no en ROW. Por supuesto, la compresión PAGE depende del tamaño del valor en la fila: probé con VARCHAR (MAX) y vi que 6000 filas de caracteres / bytes no se comprimirían, pero sí que las filas de 4000 caracteres / bytes. - Cualquier dato fuera de fila, LOB o OVERLOW = No Compression For You!
-
Si usa SQL Server 2005, o 2008 - 2016 RTM y no en Enterprise Edition, puede tener dos campos: un
VARCHAR
y unNVARCHAR
. Por ejemplo, digamos que está almacenando direcciones URL que son en su mayoría todos los caracteres ASCII básicos (valores 0 - 127) y, por lo tanto, encajan enVARCHAR
, pero a veces tienen caracteres Unicode. Su esquema puede incluir los siguientes 3 campos:... 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)) );
En este modelo, solo SELECCIONA de la columna calculada
[URL]
. Para insertar y actualizar, determina qué campo usar al ver si la conversión altera el valor entrante, que tiene que ser del tipoNVARCHAR
:INSERT INTO TableName (..., URLa, URLu) VALUES (..., IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL), IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL) );
Puede GZIP ingresar valores en
VARBINARY(MAX)
y luego descomprimirlos al salir:- Para SQL Server 2005 - 2014: puede usar SQLCLR. SQL # (una biblioteca SQLCLR que escribí) viene con Util_GZip y Util_GUnzip en la versión gratuita
- Para SQL Server 2016 y
DECOMPRESS
posteriores: puede usar las funcionesCOMPRESS
yDECOMPRESS
integradas, que también son GZip.
Si usa SQL Server 2017 o más reciente, puede considerar hacer de la tabla un Índice de almacén de columnas agrupado.
Si bien esta opción aún no es viable, SQL Server 2019 introduce soporte nativo para UTF-8 en los tipos de datos
VARCHAR
/CHAR
. Actualmente hay demasiados errores para usarlo, pero si se solucionan, esta es una opción para algunos escenarios. Para ver un análisis detallado de esta nueva característica, consulte mi publicación, " Compatibilidad con UTF-8 nativo en SQL Server 2019: ¿Salvador o falso profeta? ".
Durante los últimos años, todos nuestros proyectos han utilizado NVARCHAR para todo, ya que todos estos proyectos son multilingües. Los datos importados de fuentes externas (por ejemplo, un archivo ASCII, etc.) se convierten a Unicode antes de insertarlos en la base de datos.
Todavía no he encontrado ningún problema relacionado con el rendimiento de los índices más grandes, etc. Los índices utilizan más memoria, pero la memoria es barata.
Tanto si utiliza procedimientos almacenados como si construye SQL sobre la marcha, asegúrese de que todas las constantes de cadena tengan el prefijo N (por ejemplo, SET @foo = N''Hello world. '';), Por lo que la constante también es Unicode. Esto evita cualquier conversión de tipo de cadena en tiempo de ejecución.
YMMV.
El espacio en disco no es el problema ... pero la memoria y el rendimiento lo serán. Duplique las lecturas de la página, duplique el índice, extrañe LIKE y = comportamiento constante, etc.
¿Necesitas almacenar script chino, etc.? Si o no...
Y de MS BOL " Almacenamiento y efectos de rendimiento de Unicode "
Editar :
Pregunta reciente de SO que destaca cuán malo puede ser el rendimiento de nvarchar ...
SQL Server usa una alta CPU cuando busca dentro de cadenas nvarchar
Generalmente hablando; Comience con el tipo de datos más caro que tenga menos restricciones. Ponlo en producción . Si el rendimiento comienza a ser un problema, averigüe qué se almacena realmente en esas columnas nvarchar
. ¿Hay algún personaje allí que no encajaría en varchar
? Si no, cambie a varchar. No intente pre-optimizar antes de saber dónde está el dolor. Mi conjetura es que la elección entre nvarchar / varchar no es lo que va a ralentizar su aplicación en un futuro previsible. Habrá otras partes de la aplicación donde el ajuste del rendimiento le dará mucho más por los dólares .
Habrá casos excepcionales en los que querrá restringir deliberadamente el tipo de datos para asegurarse de que no contenga caracteres de un determinado conjunto. Por ejemplo, tuve un escenario en el que necesitaba almacenar el nombre de dominio en una base de datos. La internacionalización de los nombres de dominio no era confiable en ese momento, por lo que era mejor restringir la entrada en el nivel base y ayudar a evitar cualquier problema potencial.
Para su aplicación, nvarchar está bien porque el tamaño de la base de datos es pequeño. Decir "usar siempre nvarchar" es una gran simplificación. Si no estás obligado a almacenar cosas como Kanji u otros personajes locos, usa VARCHAR, usará mucho menos espacio. Mi predecesor en mi trabajo actual diseñó algo utilizando NVARCHAR cuando no era necesario. Recientemente lo cambiamos a VARCHAR y guardamos 15 GB solo en esa tabla (fue escrito en alto). Además, si tiene un índice en esa tabla y desea incluir esa columna o hacer un índice compuesto, acaba de aumentar el tamaño de su archivo de índice.
Apenas sea pensativo en su decisión; en el desarrollo de SQL y las definiciones de datos, rara vez parece haber una "respuesta predeterminada" (aparte de evitar los cursores a toda costa, por supuesto).
Puedo hablar por experiencia en esto, ten cuidado con nvarchar
. A menos que sea absolutamente necesario, este tipo de campo de datos destruye el rendimiento en una base de datos más grande. Heredé una base de datos que estaba dañando en términos de rendimiento y espacio. ¡Pudimos reducir el tamaño de una base de datos de 30 GB en un 70%! Se hicieron algunas otras modificaciones para ayudar con el rendimiento, pero estoy seguro de que la varchar
ayudó significativamente con eso. Si su base de datos tiene el potencial de aumentar las tablas a un millón de registros, manténgase alejado de nvarchar
a toda costa.
Si está utilizando NVARCHAR
solo porque un procedimiento almacenado del sistema lo requiere, la aparición más frecuente es inexplicablemente sp_executesql
, y su SQL dinámico es muy largo, estaría mejor desde la perspectiva del rendimiento haciendo todas las manipulaciones de cadenas (concatenación, reemplazo, etc.) en VARCHAR
luego convierte el resultado final a NVARCHAR
y lo introduce en el parámetro proc. Así que no, no siempre uses NVARCHAR
!
Siempre use nvarchar.
Es posible que nunca necesite los caracteres de doble byte para la mayoría de las aplicaciones. Sin embargo, si necesita admitir idiomas de doble byte y solo tiene soporte de un solo byte en el esquema de su base de datos, es muy costoso volver atrás y modificar toda la aplicación.
El costo de migrar una aplicación de varchar a nvarchar será mucho más que el poco espacio de disco extra que utilizará en la mayoría de las aplicaciones.
Trato con esta pregunta en el trabajo a menudo:
Fuentes de inventario y precios de FTP: las descripciones de los artículos y otros textos estaban en nvarchar cuando varchar funcionaba bien. Convertirlos a varchar redujo el tamaño del archivo casi a la mitad y realmente ayudó con las subidas.
El escenario anterior funcionó bien hasta que alguien puso un carácter especial en la descripción del artículo (tal vez marca registrada, no puedo recordar)
Todavía no uso nvarchar cada vez sobre varchar. Si hay alguna duda o potencial para caracteres especiales, uso nvarchar. Encuentro que uso varchar principalmente cuando tengo el control del 100% de lo que está poblando el campo.
nvarchar tendrá una sobrecarga significativa en la memoria, el almacenamiento, el conjunto de trabajo y la indexación, por lo que si las especificaciones dictan que nunca será necesario, no se preocupe.
No tendría una regla "siempre nvarchar" dura y rápida porque puede ser un desperdicio completo en muchas situaciones, especialmente ETL de ASCII / EBCDIC o identificadores y columnas de código que a menudo son claves y claves externas.
Por otro lado, hay muchos casos de columnas, donde me aseguraría de hacer esta pregunta antes y si no recibiera una respuesta rápida y rápida de inmediato, haría la columna nvarchar.