Heredé algunas bases de datos de SQL Server. Hay una tabla (llamaré "G"), con aproximadamente 86.7 millones de filas y 41 columnas de ancho, de una base de datos de origen (llamaré "Q") en SQL Server 2014 Standard que lleva ETL a una base de datos de destino (llamaré "P") con el mismo nombre de tabla en SQL Server 2008 R2 Standard.
es decir, [Q]. [G] ---> [P]. [G]
EDITAR: 20/03/2017: Algunas personas han preguntado si la tabla de origen es la ÚNICA fuente de la tabla de destino. Sí, es la única fuente. En lo que respecta al ETL, no ocurre ninguna transformación real; efectivamente está destinado a ser una copia 1: 1 de los datos de origen. Por lo tanto, no hay planes para agregar fuentes adicionales a esta tabla de destino.
Un poco más de la mitad de las columnas en [Q]. [G] son VARCHAR (tabla fuente):
- 13 de las columnas son VARCHAR (80)
- 9 de las columnas son VARCHAR (30)
- 2 de las columnas son VARCHAR (8).
Del mismo modo, las mismas columnas en [P]. [G] son NVARCHAR (tabla de destino), con el mismo número de columnas con los mismos anchos. (En otras palabras, la misma longitud, pero NVARCHAR).
- 13 de las columnas son NVARCHAR (80)
- 9 de las columnas son NVARCHAR (30)
- 2 de las columnas son NVARCHAR (8).
Este no es mi diseño.
Me gustaría ALTERAR [P]. [G] (destino) tipos de datos de columnas de NVARCHAR a VARCHAR. Quiero hacerlo de forma segura (sin pérdida de datos por la conversión).
¿Cómo puedo ver los valores de datos en cada columna NVARCHAR en la tabla de destino para confirmar si la columna contiene o no datos Unicode?
Una consulta (¿DMV?) Que puede verificar cada valor (en un bucle?) De cada columna NVARCHAR y decirme si ALGUNO de los valores es genuino, Unicode sería la solución ideal, pero otros métodos son bienvenidos.
fuente
[G]
ETL se transfieren a[P]
. Si[G]
es asívarchar
, y el proceso ETL es la única forma en que entran los datos[P]
, a menos que el proceso agregue verdaderos caracteres Unicode, no debería haber ninguno. Si otros procesos agregan o modifican datos[P]
, debe ser más cuidadoso, solo porque todos los datos actuales pueden servarchar
, no significa que losnvarchar
datos no puedan agregarse mañana. Del mismo modo, es posible que lo que sea que esté consumiendo los datos en datos de[P]
necesidadesnvarchar
.Respuestas:
Supongamos que una de sus columnas no contiene datos Unicode. Para verificar que necesitaría leer el valor de la columna para cada fila. A menos que tenga un índice en la columna, con una tabla de almacén de filas necesitará leer cada página de datos de la tabla. Con eso en mente, creo que tiene mucho sentido combinar todas las comprobaciones de columnas en una sola consulta en la tabla. De esa manera, no leerá los datos de la tabla muchas veces y no tendrá que codificar un cursor u otro tipo de bucle.
Para verificar una sola columna, crea que puede hacer esto:
Una conversión de
NVARCHAR
aVARCHAR
debería darte el mismo resultado, excepto si hay caracteres Unicode. Los caracteres Unicode se convertirán a?
. Entonces, el código anterior debe manejar losNULL
casos correctamente. Tiene 24 columnas para verificar, por lo que verifica cada columna en una sola consulta utilizando agregados escalares. Una implementación está abajo:Para cada columna obtendrá un resultado de
1
si alguno de sus valores contiene unicode. Un resultado de0
significa que todos los datos se pueden convertir de forma segura.Recomiendo hacer una copia de la tabla con las nuevas definiciones de columna y copiar sus datos allí. Hará conversiones costosas si lo hace en su lugar, por lo que hacer una copia podría no ser mucho más lento. Tener una copia significa que puede validar fácilmente que todos los datos todavía están allí (una forma es usar la palabra clave EXCEPT ) y puede deshacer la operación muy fácilmente.
Además, tenga en cuenta que es posible que actualmente no tenga datos Unicode, es posible que un ETL futuro cargue Unicode en una columna previamente limpia. Si no hay una verificación para esto en su proceso ETL, debería considerar agregar eso antes de hacer esta conversión.
fuente
NVARCHAR
columnaNVARCHAR
ya que ya es de ese tipo. Y no estoy seguro de cómo determinó el carácter no convertible, pero puede convertir la columnaVARBINARY
para obtener las secuencias de bytes UTF-16. Y UTF-16 es el orden inverso de bytes, entoncesp
=0x7000
y luego invierte esos dos bytes para obtener Code PointU+0070
. Pero, si la fuente es VARCHAR, entonces no puede ser un carácter Unicode. Algo más está sucediendo. Necesito más informaciónVARCHAR
se convertirá implícitamenteNVARCHAR
, pero podría ser mejor hacerloCONVERT(NVARCHAR(80), CONVERT(VARCHAR(80), column)) <> column
.SUBSTRING
a veces funciona, pero no funciona con caracteres suplementarios cuando se usan intercalaciones que no terminan_SC
, y el que usa John no funciona, aunque probablemente no sea un problema aquí. Pero la conversión a VARBINARIO siempre funciona. YCONVERT(VARCHAR(10), CONVERT(NVARCHAR(10), '›'))
no da como resultado?
, por lo que me gustaría ver los bytes. El proceso ETL podría haberlo convertido.Antes de hacer nada, considere las preguntas planteadas por @RDFozz en un comentario sobre la pregunta, a saber:
Si la respuesta es algo fuera de "Estoy 100% seguro de que esta es la única fuente de datos para esta tabla de destino", no realice ningún cambio, independientemente de si los datos actualmente en la tabla se pueden convertir o no sin pérdida de datos.
Y yo añadiría una pregunta relacionada: ¿Ha habido alguna discusión en torno a soportar múltiples idiomas en la tabla de fuente de corriente (es decir
[Q].[G]
) mediante la conversión es aNVARCHAR
?Tendrá que preguntar para tener una idea de estas posibilidades. Supongo que actualmente no le han dicho nada que apunte en esta dirección; de lo contrario, no estaría haciendo esta pregunta, pero si se supone que estas preguntas son "no", entonces deben formularse, y se les debe hacer una pregunta. audiencia lo suficientemente amplia como para obtener la respuesta más precisa / completa.
El problema principal aquí no es tanto tener puntos de código Unicode que no se pueden convertir (nunca), sino más bien tener puntos de código que no encajen en una sola página de códigos. Eso es lo bueno de Unicode: puede contener caracteres de TODAS las páginas de códigos. Si realiza la conversión desde
NVARCHAR
, donde no necesita preocuparse por las páginas de códigos, aVARCHAR
, deberá asegurarse de que la Clasificación de la columna de destino esté utilizando la misma página de códigos que la columna de origen. Esto supone tener una sola fuente o múltiples fuentes usando la misma página de códigos (aunque no necesariamente la misma Clasificación). Pero si hay varias fuentes con varias páginas de códigos, entonces puede encontrarse con el siguiente problema:Devoluciones (segundo conjunto de resultados):
Como puede ver, todos esos caracteres se pueden convertir
VARCHAR
, pero no en la mismaVARCHAR
columna.Use la siguiente consulta para determinar cuál es la página de códigos para cada columna de su tabla de origen:
HABIENDO DICHO ESO....
Usted mencionó estar en SQL Server 2008 R2, PERO, no dijo qué edición. Si se encuentra en Enterprise Edition, olvídese de todas estas cosas de conversión (ya que probablemente lo esté haciendo solo para ahorrar espacio) y habilite la compresión de datos:
Implementación de compresión Unicode
Si usa Standard Edition (y ahora parece que usted es then), entonces hay otra posibilidad muy remota: la actualización a SQL Server 2016 ya que SP1 incluye la capacidad de todas las ediciones para usar Compresión de datos (recuerde, dije "posibilidad remota "😉).
Por supuesto, ahora que se acaba de aclarar que solo hay una fuente para los datos, entonces no tiene nada de qué preocuparse, ya que la fuente no puede contener caracteres exclusivos de Unicode o caracteres fuera de su código específico. página. En ese caso, lo único que debe tener en cuenta es usar la misma Clasificación que la columna de origen, o al menos una que use la misma Página de códigos. Es decir, si la columna de origen está usando
SQL_Latin1_General_CP1_CI_AS
, entonces podría usarLatin1_General_100_CI_AS
en el destino.Una vez que sepa qué colación usar, puede:
ALTER TABLE ... ALTER COLUMN ...
serVARCHAR
(asegúrese de especificar la corrienteNULL
/NOT NULL
ajuste), lo que requiere un poco de tiempo y una gran cantidad de espacio de registro de transacciones de 87 millones de filas, ORCree nuevas columnas "ColumnName_tmp" para cada una y complete lentamente
UPDATE
haciendoTOP (1000) ... WHERE new_column IS NULL
. Una vez que todas las filas están pobladas (¡y validado que todas se copiaron correctamente! Es posible que necesite un activador para manejar ACTUALIZACIONES, si las hay), en una transacción explícita, usesp_rename
para intercambiar los nombres de columna de las columnas "actuales" por " _Old "y luego las nuevas columnas" _tmp "para simplemente eliminar el" _tmp "de los nombres. Luego llamesp_reconfigure
a la tabla para invalidar cualquier plan en caché que haga referencia a la tabla, y si hay Vistas que hagan referencia a la tabla, deberá llamarsp_refreshview
(o algo así). Una vez que haya validado la aplicación y ETL esté funcionando correctamente con ella, puede soltar las columnas.fuente
Latin1_General_100_CI_AS
es mucho mejor que la que está utilizando. Significa fácilmente que el comportamiento de clasificación y comparación será el mismo entre ellos, incluso si no es tan bueno como la nueva Colación que acabo de mencionar.Tengo algo de experiencia con esto cuando tenía un trabajo real. Como en ese momento quería preservar los datos base, y también tenía que dar cuenta de los nuevos datos que posiblemente podrían tener caracteres que se perderían en la confusión, elegí una columna computada no persistente.
Aquí hay un ejemplo rápido usando una copia de la base de datos Super User del volcado de datos SO .
Podemos ver de inmediato que hay DisplayNames con caracteres Unicode:
¡Agreguemos una columna calculada para calcular cuántos! La columna DisplayName es
NVARCHAR(40)
.El recuento devuelve ~ 3000 filas
Sin embargo, el plan de ejecución es un poco pesado. La consulta finaliza rápidamente, pero este conjunto de datos no es terriblemente grande.
Dado que las columnas calculadas no necesitan persistir para agregar un índice, podemos hacer una de estas:
Lo que nos da un plan un poco más ordenado:
Entiendo si esto no es la respuesta, ya que implica cambios arquitectónicos, pero teniendo en cuenta el tamaño de los datos, probablemente esté buscando agregar índices para hacer frente a las consultas que de todos modos se unen a la tabla.
¡Espero que esto ayude!
fuente
Usando el ejemplo en Cómo verificar si un campo contiene datos Unicode , puede leer los datos en cada columna y hacer lo siguiente
CAST
y verificar:fuente