Saltar al contenido

¿Cuándo se usará `nvarchar / nchar` con SQL Server 2019?

Hola usuario de nuestra web, hallamos la respuesta a lo que andabas buscando, has scroll y la obtendrás aquí.

Solución:

La compatibilidad con UTF-8 le ofrece un nuevo conjunto de opciones. El ahorro potencial de espacio (sin compresión de filas o páginas) es una consideración, pero la elección del tipo y la codificación probablemente debería hacerse principalmente sobre la base de los requisitos reales de comparación, clasificación, importación y exportación de datos.

Es posible que deba cambiar más de lo que cree, ya que, por ejemplo, un nchar(1) type proporciona dos bytes de almacenamiento. Eso es suficiente para almacenar cualquier carácter en BMP (puntos de código 000000 a 00FFFF). Algunos de los caracteres en ese rango se codificarían con solo 1 byte en UTF-8, mientras que otros requerirían 2 o incluso 3 bytes (consulte esta tabla de comparación para obtener más detalles). Por lo tanto, garantizar la cobertura del mismo conjunto de caracteres en UTF-8 requeriría char(3).

Por ejemplo:

DECLARE @T AS table 
(
    n integer PRIMARY KEY,
    UTF16 nchar(1) COLLATE Latin1_General_CI_AS,
    UTF8 char(1) COLLATE Latin1_General_100_CI_AS_SC_UTF8
);

INSERT @T (n, UTF16, UTF8)
SELECT 911, NCHAR(911), NCHAR(911);

da el error familiar:

Msj 8152, nivel 16, estado 30, línea xxx
Cadena o datos binarios podrían truncarse.

O si el indicador de seguimiento 460 está activo:

Msj 2628, nivel 16, estado 1, línea xxx
Los datos binarios o de cadena se truncarían en la tabla ‘@T’, columna ‘UTF8’. Valor truncado: ”.

Expandiendo la columna UTF8 para char(2) o varchar(2) resuelve el error para NCHAR(911):

DECLARE @T AS table 
(
    n integer PRIMARY KEY,
    UTF16 nchar(1) COLLATE Latin1_General_CI_AS,
    UTF8 varchar(2) COLLATE Latin1_General_100_CI_AS_SC_UTF8
);

INSERT @T (n, UTF16, UTF8)
SELECT 911, NCHAR(911), NCHAR(911);

Sin embargo, si fue por ejemplo NCHAR(8364), necesitaría expandir la columna aún más, para char(3) o varchar(3).

Tenga en cuenta también que todas las intercalaciones UTF-8 utilizan caracteres suplementarios, por lo que no funcionarán con la replicación.

Aparte de cualquier otra cosa, la compatibilidad con UTF-8 solo está en vista previa en este momento, por lo que no está disponible para uso en producción.

esta pueden reducir el tamaño de tablas e índices (énfasis agregado)

La reducción de tamaño solo es posible si la mayoría de los personajes son esencialmente [space], 0 - 9, A - Z, a - zy algo de puntuación básica. Fuera de ese conjunto específico de caracteres (en términos de uso práctico, valores ASCII estándar 32-126), será a lo mejor igual en tamaño a NVARCHAR / UTF-16, o en muchos casos más grande.

Estoy planeando migrar los datos, ya que creo que leer menos datos conducirá a un mejor rendimiento del sistema.

Ten cuidado. UTF-8 no es un interruptor mágico para “arreglar todo”. En igualdad de condiciones, sí, leer menos mejora el rendimiento. Pero aquí “todas las demás cosas” son no igual. Incluso al almacenar solamente caracteres ASCII estándar (lo que significa: todos los caracteres son de 1 byte, por lo que requieren la mitad del espacio en comparación con el almacenamiento en NVARCHAR), existe una pequeña penalización en el rendimiento por usar UTF-8. Creo que el problema se debe a que UTF-8 es una codificación de longitud variable, lo que significa que cada byte debe interpretarse a medida que se lee para saber si es un carácter completo o si el siguiente byte es parte de él. Esto significa que todos string las operaciones deben comenzar desde el principio y continuar byte a byte. Por otra parte, NVARCHAR / UTF-16 es siempre de 2 bytes (incluso los caracteres suplementarios se componen de dos puntos de código de 2 bytes), por lo que todo se puede leer en fragmentos de 2 bytes.

En mis pruebas, incluso con solamente caracteres ASCII estándar, almacenar los datos como UTF-8 no proporcionó ningún ahorro de tiempo transcurrido, pero definitivamente fue peor para el tiempo de CPU. Y eso fue sin la compresión de datos, por lo que al menos se usó menos espacio en disco. Pero, al usar la compresión, el espacio requerido para UTF-8 era solo entre un 1% y un 1,5% más pequeño. Por lo tanto, no hay ahorro de espacio y más tiempo de CPU para UTF-8.

Las cosas se complican al usar NVARCHAR(MAX) ya que la compresión Unicode no funciona con ese tipo de datos, incluso si el valor es lo suficientemente pequeño como para almacenarse en una fila. Pero, si los datos son lo suficientemente pequeños, aún deberían beneficiarse de la compresión de filas o páginas (en cuyo caso en realidad se vuelve más rápido que UTF-8). Sin embargo, los datos fuera de la fila no pueden utilizar ninguna compresión. Aun así, convertir la tabla en un índice de almacén de columnas agrupado reduce en gran medida el tamaño de NVARCHAR(MAX) (incluso si todavía es un poco más grande que UTF-8 cuando se usa Clustered Columnstore Index).

¿Alguien puede señalar un escenario y una razón para no usar los tipos de datos char con codificación UTF?

Definitivamente. De hecho, no encuentro una razón convincente para usarlo en la mayoría de los casos. El único escenario que realmente se beneficia de UTF-8 es:

  1. Los datos son principalmente ASCII estándar (valores 0-127)
  2. Debe ser Unicode porque podría necesita almacenar una gama más amplia de caracteres que los que están disponibles en cualquier página de códigos de 8 bits (es decir, VARCHAR)
  3. La mayoría de los datos se almacenan fuera de la fila (por lo que la compresión de páginas ni siquiera funciona)
  4. Tiene suficientes datos que necesita / desea reducir el tamaño por razones que no son de rendimiento de consultas (por ejemplo, reducir el tamaño de la copia de seguridad, reducir el tiempo requerido para la copia de seguridad / restauración, etc.)
  5. No puede usar Clustered Columnstore Index (¿quizás el uso de la tabla empeora el rendimiento en este caso?)

Mis pruebas muestran que en casi todos los casos, NVARCHAR fue más rápido, especialmente cuando había más datos. De hecho, 21.000 filas con un promedio de 5.000 caracteres por fila se requieren 165 MB para UTF-8 y 236 MB para NVARCHAR sin comprimir. Y sin embargo el NVARCHAR fue 2 veces más rápido en tiempo transcurrido y al menos 2 veces más rápido (a veces más) en tiempo de CPU. Aún así, ocupó 71 MB más en disco.

Fuera de eso, todavía no recomendaría usar UTF-8, al menos a partir de CTP 2, debido a una variedad de errores que he encontrado en esta función.

Para obtener un análisis detallado de esta nueva función, incluida una explicación de las diferencias entre UTF-16 y UTF-8, y una lista de esos errores, consulte mi publicación:

Compatibilidad nativa con UTF-8 en SQL Server 2019: ¿Salvador o falso profeta?

Si para ti ha resultado de ayuda este post, sería de mucha ayuda si lo compartes con más entusiastas de la programación de esta manera contrubuyes a difundir esta información.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *