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

11

Con SQL Server 2019, Microsoft presenta soporte para UTF-8CHAR y VARCHARtipos de datos y dice:

Esta característica puede proporcionar importantes ahorros de almacenamiento, dependiendo del juego de caracteres en uso. Por ejemplo, cambiar un tipo de datos de columna existente con cadenas ASCII de NCHAR (10) a CHAR (10) utilizando una clasificación habilitada para UTF-8, se traduce en una reducción de casi el 50% en los requisitos de almacenamiento. Esta reducción se debe a que NCHAR (10) requiere 22 bytes para el almacenamiento, mientras que CHAR (10) requiere 12 bytes para la misma cadena Unicode.

UTF-8 parece admitir todos los scripts, por lo que básicamente podemos comenzar a almacenar datos Unicode varchary charcolumnas. Y como se dice en la documentación, esto puede reducir el tamaño de las tablas e índices, y a partir de ahí podemos obtener un rendimiento aún mejor, porque se lee una menor cantidad de datos.

Me pregunto si esto significa que podemos dejar de usar nvarchary ncharcolumnas que implementan UTF-16.

¿Alguien puede señalar un escenario y una razón, para no usar los tipos de datos char con UTFcodificación y continuar usando los n-chars?

gotqn
fuente
¿Por qué no lo prueba e informa? También infórmenos cuánto esfuerzo realizó para convertir de nvarchar a varchar, cuánto tiempo tomaron las tablas alternativas, cuánto tiempo pasó probando y qué problemas encontró.
Colin 't Hart
@ Colin'tHart Si no hay problemas conocidos o consideraciones, estoy planeando migrar los datos, ya que creo que leer menos datos conducirá a un mejor rendimiento del sistema. Acerca de la conversión, llevará tiempo, por supuesto, especialmente si tiene índices con la columna dada, deben reconstruirse, pero creo que valdrá la pena. Por supuesto, voy a probar pronto el impacto en el rendimiento, solo buscando cualquier problema que haga innecesaria la migración.
gotqn
Tenga en cuenta que SQL Server admite la compresión Unicode para columnas NVarchar cuando se utiliza la compresión PAGE o ROW. docs.microsoft.com/en-us/sql/relational-databases/…
David Browne - Microsoft
1
Vale la pena señalar que si bien UTF-8 puede ahorrar espacio si está almacenando "datos similares a ASCII", no es una compresión en sí misma y no debe confundirse como tal. Por ejemplo, si está almacenando principalmente nombres chinos en una base de datos, sería peor usar los CHARtipos UTF-8 que los tipos Unicode (con o sin compresión, ya que, en última instancia, los datos deben descomprimirse para procesarse). Considere también que el tipo de cadena nativa de Windows es Unicode, por lo que las cadenas UTF-8 a menudo necesitan ser decodificadas. Las compensaciones involucradas significan que no es probable que los Ntipos sean retirados en el corto plazo.
Jeroen Mostert
1
La "aplicación asesina" n. ° 1 para UTF-8 CHARes probablemente SQL Server en Linux, si el motor obtiene soporte nativo para procesar cadenas directamente como UTF-8, aquí UTF-8 es el conjunto de caracteres "nativo" (más o menos) y mantener las cadenas como UTF-16 es la alternativa menos eficiente. Tampoco está de más usarlo en Windows en lugares donde ya lo está utilizando CHAR, por supuesto, ya que las colaciones que restringen los caracteres que se pueden almacenar nunca han sido atractivas.
Jeroen Mostert

Respuestas:

6

Esto puede reducir el tamaño de las tablas e índices (énfasis agregado)

Reducción en el tamaño sólo es posible si la mayoría de los personajes son esencialmente [space], 0 - 9, A - Z, a - z, y algunos puntuacion básica. Fuera de ese conjunto específico de caracteres (en términos prácticos de uso, valores ASCII estándar 32 - 126), será, en el mejor de los casos, de tamaño igual 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" no son iguales. Incluso cuando se almacenan solo caracteres ASCII estándar (es decir: todos los caracteres son de 1 byte, por lo tanto requieren la mitad del espacio en comparación con el almacenamiento NVARCHAR), existe una leve penalización de 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 todas las operaciones de cadena deben comenzar desde el principio y continuar byte por byte. Por otra parte,NVARCHAR / UTF-16 siempre tiene 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 solo caracteres ASCII estándar, el almacenamiento de 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 compresión de datos, por lo que al menos se utilizó menos espacio en disco. Pero, al usar la compresión, el espacio requerido para UTF-8 era solo 1% - 1.5% más pequeño. Por lo tanto, efectivamente no hay ahorro de espacio y un mayor tiempo de CPU para UTF-8.

Las cosas se vuelven más complicadas cuando se usa, 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 fila. Pero, si los datos son lo suficientemente pequeños, aún deberían beneficiarse de la compresión de fila o página (en cuyo caso, en realidad se vuelve más rápido que UTF-8). Sin embargo, los datos fuera de fila no pueden usar ninguna compresión. Aún así, hacer que la tabla sea 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 utiliza el índice de almacén de columnas agrupado).

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

Seguro. De hecho, realmente 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 en su mayoría ASCII estándar (valores 0-127)
  2. Debe ser Unicode porque puede necesitar almacenar un rango de caracteres más amplio que el que está disponible 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ágina ni siquiera funciona)
  4. Tiene suficientes datos que necesita / desea reducir el tamaño por razones que no son de rendimiento de consulta (por ejemplo, reduzca el tamaño de la copia de seguridad, reduzca el tiempo requerido para la copia de seguridad / restauración, etc.)
  5. No puede usar el índice de almacén de columnas en clúster (¿tal vez el uso de la tabla empeora el rendimiento en este caso?)

Mi prueba muestra que en casi todos los casos, NVARCHAR fue más rápido, especialmente cuando había más datos. De hecho, 21k filas con un promedio de 5k caracteres por fila requirieron 165 MB para UTF-8 y 236 MB para NVARCHARsin comprimir. Y, sin embargo, NVARCHARfue 2 veces más rápido en el tiempo transcurrido, y al menos 2 veces más rápido (a veces más) en tiempo de CPU. Aún así, tomó 71 MB más en el 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 un análisis detallado de esta nueva característica, incluida una explicación de las diferencias entre UTF-16 y UTF-8, y una lista de esos errores, consulte mi publicación:

Soporte nativo de UTF-8 en SQL Server 2019: ¿Salvador o falso profeta?

Solomon Rutzky
fuente
12

La compatibilidad con UTF-8 le ofrece un nuevo conjunto de opciones. El ahorro potencial de espacio (sin compresión de fila o página ) es una consideración, pero la elección del tipo y la codificación probablemente se debe realizar principalmente en función de los requisitos reales de comparación, clasificación, importación y exportación de datos .

Es posible que necesite cambiar más de lo que piensa, ya que, por ejemplo, un nchar(1)tipo 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:

El mensaje 8152, Nivel 16, Estado 30, Línea xxx
Cadena o datos binarios se truncarían.

O si la marca de seguimiento 460 está activa:

El mensaje 2628, Nivel 16, Estado 1, Línea xxx
Cadena o datos binarios se truncaría en la tabla '@T', columna 'UTF8'. Valor truncado: ''.

Expandir la columna UTF8 char(2)o varchar(2)resolver 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 fuera NCHAR(8364), por ejemplo , necesitaría expandir la columna aún más, char(3)ao varchar(3).

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

Aparte de cualquier otra cosa, el soporte UTF-8 solo está en versión preliminar en este momento, por lo que no está disponible para uso en producción.

Paul White 9
fuente