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 con claridad.
Primero: Do no siempre se utilizan NVARCHAR
. Esa es una actitud / enfoque muy peligroso, y a menudo costoso. Y no es mejor decir " Nunca use cursores" ya que a veces son los medios más eficientes para resolver un problema en particular, y la solución común de hacer un WHILE
bucle casi siempre será más lenta que una correcta. Cursor hecho .
La única vez que debe usar el término "siempre" es cuando aconseja "hacer siempre lo mejor para la situación". Es cierto que a menudo es difícil de determinar, especialmente cuando se trata de equilibrar las ganancias a corto plazo en el tiempo de desarrollo (gerente: "necesitamos esta característica, que no conocías hasta ahora, ¡hace una semana!") 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é estamos teniendo estos problemas de rendimiento? ¿Cómo podríamos haber hecho X que no tiene flexibilidad? No podemos pagar un sprint o dos para arreglar esto. ¿Qué podemos hacer en una semana para volver a nuestros elementos prioritarios? ¡Y definitivamente necesitamos pasar más tiempo en el diseño para que esto no siga sucediendo! ").
Segundo: la respuesta de @ gbn toca algunos puntos muy importantes a considerar al tomar ciertas decisiones de modelado de datos cuando la ruta no es 100% clara. Pero aún hay más para considerar:
- tamaño de los archivos de registro de transacciones
- tiempo que lleva replicarse (si usa la replicación)
- tiempo que tarda ETL (si ETLing)
- tiempo que lleva enviar registros a un sistema remoto y restaurarlos (si se utiliza el envío de registros)
- tamaño de las copias de seguridad
- tiempo que lleva completar la copia de seguridad
- cuánto tiempo lleva hacer una restauración (esto podría ser importante algún día ;-)
- tamaño necesario para tempdb
- rendimiento de los desencadenantes (para tablas insertadas y eliminadas que se almacenan en tempdb)
- rendimiento del control de versiones de filas (si se usa SNAPSHOT ISOLATION, ya que el almacén de versiones está en tempdb)
- capacidad de obtener nuevo espacio en disco cuando el CFO dice que el año pasado gastaron $ 1 millón en una SAN y, por lo tanto, no autorizarán otros $ 250k para almacenamiento adicional
- tiempo que lleva realizar las operaciones INSERTAR y ACTUALIZAR
- cantidad de tiempo que lleva hacer el mantenimiento del índice
- etc, etc, etc.
El desperdicio de espacio tiene un enorme efecto en cascada en todo el sistema. Escribí un artículo con detalles explícitos sobre este tema: ¡El disco es barato! ORLY? (Se requiere registro gratuito; lo siento, no controlo esa política).
Tercero: si bien algunas respuestas se centran incorrectamente en el aspecto "esta es una aplicación pequeña", y algunas sugieren correctamente "usar lo que es apropiado", ninguna de las respuestas ha proporcionado 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. ¡Excelente! Entonces 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 aparezcan en esos lugares.
- ¿Pero para la dirección y los nombres de las ciudades? No se especificó el propósito de la aplicación (hubiera sido útil), pero suponiendo que los registros de direcciones, si los hubiera, pertenezcan solo a una región geográfica particular (es decir, un solo idioma / cultura), utilícelos
VARCHAR
con la página de códigos apropiada (que se determina a partir de la clasificación del campo).
- Si almacenar códigos de Estado y / o ISO del país (sin necesidad de almacenar
INT
/ TINYINT
longitud ya que los códigos ISO son fijos, legible por humanos, y así, :) uso estándar CHAR(2)
de códigos de dos letras, y CHAR(3)
si se usa 3 códigos de letras. Y considere usar una intercalación binaria como Latin1_General_100_BIN2
.
- Si almacena códigos postales (es decir, códigos postales), utilícelos
VARCHAR
ya que es un estándar internacional no utilizar nunca ninguna letra fuera de AZ. Y sí, aún use VARCHAR
incluso si solo almacena códigos postales de EE. UU. Y no INT, ya que los códigos postales no son números, son cadenas, y algunos de ellos tienen un "0" inicial. Y considere usar una intercalación binaria como Latin1_General_100_BIN2
.
- Si almacena direcciones de correo electrónico y / o URL, úselos
NVARCHAR
ya que ambos pueden contener caracteres Unicode.
- y así....
Cuarto: ahora que tiene NVARCHAR
datos que ocupan el doble de espacio del necesario para los datos que encajan bien VARCHAR
("encaja 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 algunas contienen caracteres Unicode, por lo que debe mantenerlas NVARCHAR
, considere lo siguiente:
Si está utilizando SQL Server 2008 - 2016 RTM y está en Enterprise Edition, O si está utilizando SQL Server 2016 SP1 (que hizo que la compresión de datos esté disponible en todas las ediciones) o posterior, puede habilitar la compresión de datos . La compresión de datos puede (pero no "siempre") comprimir datos Unicode en NCHAR
y NVARCHAR
campos. Los factores determinantes son:
NCHAR(1 - 4000)
y NVARCHAR(1 - 4000)
use el Esquema de compresión estándar para Unicode , pero solo a partir de SQL Server 2008 R2, ¡Y solo para datos IN ROW, no OVERFLOW! Esto parece ser mejor que el algoritmo de compresión ROW / PAGE normal.
NVARCHAR(MAX)
y XML
(y supongo que también VARBINARY(MAX)
, TEXT
y NTEXT
) los datos que están EN LA FILA (no fuera de la fila en las páginas LOB o OVERFLOW) pueden al menos comprimirse en PÁGINA, pero no en ROW. Por supuesto, la compresión PAGE depende del tamaño del valor en fila: probé con VARCHAR (MAX) y vi que las filas de 6000 caracteres / bytes no se comprimirían, pero las filas de 4000 caracteres / bytes sí.
- Cualquier dato OFF ROW, LOB u OVERLOW = ¡Sin compresión para usted!
Si usa SQL Server 2005 o 2008 - 2016 RTM y no está en Enterprise Edition, puede tener dos campos: uno VARCHAR
y uno NVARCHAR
. Por ejemplo, supongamos que está almacenando URL que en su mayoría son caracteres ASCII básicos (valores 0-127) y, por lo tanto, se ajustan VARCHAR
, 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 [URL]
columna calculada. Para insertar y actualizar, usted determina qué campo usar al ver si la conversión altera el valor entrante, que debe ser de NVARCHAR
tipo:
INSERT INTO TableName (..., URLa, URLu)
VALUES (...,
IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
);
Puede GZIP valores entrantes VARBINARY(MAX)
y luego descomprimir 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 versiones posteriores: puede usar las funciones
COMPRESS
y DECOMPRESS
incorporadas, que también son GZip.
Si usa SQL Server 2017 o más reciente, puede considerar convertir la tabla en un Índice de almacén de columnas en clúster.
Si bien aún no es una opción viable, SQL Server 2019 presenta soporte nativo para UTF-8 en VARCHAR
/ CHAR
datatypes. Actualmente hay demasiados errores para que pueda usarse, pero si se corrigen, esta es una opción para algunos escenarios. Consulte mi publicación, " Soporte nativo de UTF-8 en SQL Server 2019: ¿Salvador o falso profeta? ", Para un análisis detallado de esta nueva característica.