Con SQL Server 2019, Microsoft presenta soporte para UTF-8CHAR
y VARCHAR
tipos 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 varchar
y char
columnas. 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 nvarchar
y nchar
columnas que implementan UTF-16.
¿Alguien puede señalar un escenario y una razón, para no usar los tipos de datos char con UTF
codificación y continuar usando los n-chars?
CHAR
tipos 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 losN
tipos sean retirados en el corto plazo.CHAR
es 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á utilizandoCHAR
, por supuesto, ya que las colaciones que restringen los caracteres que se pueden almacenar nunca han sido atractivas.Respuestas:
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 aNVARCHAR
/ UTF-16, o en muchos casos más grande.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 deNVARCHAR(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).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:
VARCHAR
)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
NVARCHAR
sin comprimir. Y, sin embargo,NVARCHAR
fue 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?
fuente
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íachar(3)
.Por ejemplo:
da el error familiar:
O si la marca de seguimiento 460 está activa:
Expandir la columna UTF8
char(2)
ovarchar(2)
resolver el error paraNCHAR(911)
:Sin embargo, si fuera
NCHAR(8364)
, por ejemplo , necesitaría expandir la columna aún más,char(3)
aovarchar(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.
fuente