Al pasar de SQL 2005 [SQL_Latin1_General_CP1_CI_AS] a 2008, perderé cualquier característica al usar 'compatibilidad con versiones anteriores'

18

Estamos pasando de SQL 2005 [La instancia y la base de datos tienen intercalación de SQL_Latin1_General_CP1_CI_AS] a SQL 2008 [que por defecto es Latin1_General_CI_AS].

Completé una instalación de SQL 2008 R2 y utilicé la Latin1_General_CI_ASintercalación predeterminada , con la restauración de la base de datos aún activa SQL_Latin1_General_CP1_CI_AS. Se produjeron los problemas exceptuados: las tablas #temp estaban dentro Latin1_General_CI_ASmientras el db estaba dentro SQL_Latin1_General_CP1_CI_ASy aquí es donde estoy ahora. Necesito asesoramiento sobre las trampas ahora, por favor.

En la instalación de SQL Server 2008 R2, tengo la opción de instalación para su uso 'SQL Collation, used for backwards compatibility'en el que tengo la opción de seleccionar la misma intercalación que la base de datos 2005: SQL_Latin1_General_CP1_CI_AS.

  1. Esto me permitirá no tener problemas con las tablas #temp, pero ¿existen dificultades?

  2. ¿Perdería alguna funcionalidad o características de cualquier tipo al no utilizar una recopilación "actual" de SQL 2008?

  3. ¿Qué pasa cuando nos mudamos (por ejemplo, en 2 años) de 2008 a SQL 2012? ¿Tendré problemas entonces?
  4. ¿En algún momento me verían obligado a ir Latin1_General_CI_AS?

  5. Leí que algunos scripts de DBA completan las filas de bases de datos completas, y luego ejecuto el script de inserción en la base de datos con la nueva recopilación.

Peter PitLock
fuente
2
Si cree que puede ingresar a Hekaton en SQL Server 2014, aquí hay algo más que puede considerar leer .
Aaron Bertrand

Respuestas:

20

En primer lugar, disculpas por una respuesta tan larga, ya que siento que todavía hay mucha confusión cuando la gente habla de términos como cotejo, orden de clasificación, página de códigos, etc.

De BOL :

Las intercalaciones en SQL Server proporcionan reglas de clasificación, mayúsculas y minúsculas y propiedades de sensibilidad de acento para sus datos . Las intercalaciones que se usan con los tipos de datos de caracteres como char y varchar dictan la página de códigos y los caracteres correspondientes que se pueden representar para ese tipo de datos. Ya sea que esté instalando una nueva instancia de SQL Server, restaurando una copia de seguridad de la base de datos o conectando el servidor a las bases de datos del cliente, es importante que comprenda los requisitos locales, el orden de clasificación y la sensibilidad a mayúsculas y minúsculas de los datos con los que trabajará. .

Esto significa que la Clasificación es muy importante ya que especifica reglas sobre cómo se ordenan y comparan las cadenas de caracteres de los datos.

Nota: Más información sobre PROPIEDAD DE COLECCIÓN

Ahora, primero entendamos las diferencias ......

Ejecutando debajo de T-SQL:

SELECT *
FROM::fn_helpcollations()
WHERE NAME IN (
        'SQL_Latin1_General_CP1_CI_AS'
        ,'Latin1_General_CI_AS'
        )
GO

SELECT 'SQL_Latin1_General_CP1_CI_AS' AS 'Collation'
    ,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'CodePage') AS 'CodePage'
    ,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'LCID') AS 'LCID'
    ,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'ComparisonStyle') AS 'ComparisonStyle'
    ,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'Version') AS 'Version'

UNION ALL

SELECT 'Latin1_General_CI_AS' AS 'Collation'
    ,COLLATIONPROPERTY('Latin1_General_CI_AS', 'CodePage') AS 'CodePage'
    ,COLLATIONPROPERTY('Latin1_General_CI_AS', 'LCID') AS 'LCID'
    ,COLLATIONPROPERTY('Latin1_General_CI_AS', 'ComparisonStyle') AS 'ComparisonStyle'
    ,COLLATIONPROPERTY('Latin1_General_CI_AS', 'Version') AS 'Version'
GO

Los resultados serían:

ingrese la descripción de la imagen aquí

Mirando los resultados anteriores, la única diferencia es el Orden de clasificación entre las 2 intercalaciones, pero eso no es cierto, lo que puede ver por qué de la siguiente manera:

Prueba 1:

--Clean up previous query
IF OBJECT_ID('Table_Latin1_General_CI_AS') IS NOT NULL
    DROP TABLE Table_Latin1_General_CI_AS;

IF OBJECT_ID('Table_SQL_Latin1_General_CP1_CI_AS') IS NOT NULL
    DROP TABLE Table_SQL_Latin1_General_CP1_CI_AS;

-- Create a table using collation Latin1_General_CI_AS 
CREATE TABLE Table_Latin1_General_CI_AS (
    ID INT IDENTITY(1, 1)
    ,Comments VARCHAR(50) COLLATE Latin1_General_CI_AS
    )

-- add some data to it 
INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('kin_test1')

INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('Kin_Tester1')

-- Create second table using collation SQL_Latin1_General_CP1_CI_AS 
CREATE TABLE Table_SQL_Latin1_General_CP1_CI_AS (
    ID INT IDENTITY(1, 1)
    ,Comments VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS
    )

-- add some data to it 
INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('kin_test1')

INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('Kin_Tester1')

--Now try to join both tables
SELECT *
FROM Table_Latin1_General_CI_AS LG
INNER JOIN Table_SQL_Latin1_General_CP1_CI_AS SLG ON LG.Comments = SLG.Comments
GO

Resultados de la Prueba 1:

Msg 468, Level 16, State 9, Line 35
Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "Latin1_General_CI_AS" in the equal to operation.

A partir de los resultados anteriores, podemos ver que no podemos comparar directamente los valores en columnas con diferentes intercalaciones, debe usar COLLATEpara comparar los valores de las columnas.

PRUEBA 2:

La principal diferencia es el rendimiento, como señala Erland Sommarskog en esta discusión sobre msdn .

--Clean up previous query
IF OBJECT_ID('Table_Latin1_General_CI_AS') IS NOT NULL
    DROP TABLE Table_Latin1_General_CI_AS;

IF OBJECT_ID('Table_SQL_Latin1_General_CP1_CI_AS') IS NOT NULL
    DROP TABLE Table_SQL_Latin1_General_CP1_CI_AS;

-- Create a table using collation Latin1_General_CI_AS 
CREATE TABLE Table_Latin1_General_CI_AS (
    ID INT IDENTITY(1, 1)
    ,Comments VARCHAR(50) COLLATE Latin1_General_CI_AS
    )

-- add some data to it 
INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('kin_test1')

INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('kin_tester1')

-- Create second table using collation SQL_Latin1_General_CP1_CI_AS 
CREATE TABLE Table_SQL_Latin1_General_CP1_CI_AS (
    ID INT IDENTITY(1, 1)
    ,Comments VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS
    )

-- add some data to it 
INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('kin_test1')

INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('kin_tester1')

--- Crear índices en ambas tablas

CREATE INDEX IX_LG_Comments ON  Table_Latin1_General_CI_AS(Comments)
go
CREATE INDEX IX_SLG_Comments ON  Table_SQL_Latin1_General_CP1_CI_AS(Comments)

--- Ejecuta las consultas

DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_Latin1_General_CI_AS WHERE Comments = 'kin_test1'
GO

--- Esto tendrá conversión IMPLÍCITA

ingrese la descripción de la imagen aquí

--- Ejecuta las consultas

DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_SQL_Latin1_General_CP1_CI_AS WHERE Comments = 'kin_test1'
GO

--- Esto NO tendrá conversión IMPLÍCITA

ingrese la descripción de la imagen aquí

La razón para la conversión implícita es porque, tengo mi base de datos y la clasificación del servidor como SQL_Latin1_General_CP1_CI_ASy la tabla Table_Latin1_General_CI_AS tiene una columna Comentarios definidos como VARCHAR(50)con COLLATE Latin1_General_CI_AS , por lo que durante la búsqueda, SQL Server tiene que hacer una conversión IMPLICIT.

Prueba 3:

Con la misma configuración, ahora compararemos las columnas varchar con los valores nvarchar para ver los cambios en los planes de ejecución.

- ejecuta la consulta

DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_Latin1_General_CI_AS WHERE Comments =  (SELECT N'kin_test1' COLLATE Latin1_General_CI_AS)
GO

ingrese la descripción de la imagen aquí

- ejecuta la consulta

DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_SQL_Latin1_General_CP1_CI_AS WHERE Comments = N'kin_test1'
GO

ingrese la descripción de la imagen aquí

Tenga en cuenta que la primera consulta puede realizar la búsqueda de índice, pero tiene que hacer la conversión implícita, mientras que la segunda realiza una exploración de índice que resulta ineficiente en términos de rendimiento cuando explora tablas grandes.

Conclusión

  • Todas las pruebas anteriores muestran que tener una clasificación correcta es muy importante para la instancia del servidor de la base de datos.
  • SQL_Latin1_General_CP1_CI_AS es una recopilación de SQL con las reglas que le permiten ordenar los datos para unicode y no unicode son diferentes.
  • La intercalación de SQL no podrá usar Index al comparar datos unicode y no unicode como se ve en las pruebas anteriores que al comparar los datos nvarchar con los datos varchar, escanea el índice y no busca.
  • Latin1_General_CI_AS es una recopilación de Windows con las reglas que le permiten ordenar los datos para unicode y no unicode son los mismos.
  • La intercalación de Windows todavía puede usar el índice (búsqueda de índice en el ejemplo anterior) al comparar datos unicode y no unicode, pero ve una ligera penalización de rendimiento.
  • Recomiendo leer Erland Sommarskog respuesta + los elementos de conexión que ha señalado.

Esto me permitirá no tener problemas con las tablas #temp, pero ¿existen dificultades?

Vea mi respuesta arriba.

¿Perdería alguna funcionalidad o características de cualquier tipo al no utilizar una recopilación "actual" de SQL 2008?

Todo depende de la funcionalidad / características a las que se refiera. La clasificación es el almacenamiento y la clasificación de datos.

¿Qué pasa cuando nos mudamos (por ejemplo, en 2 años) de 2008 a SQL 2012? ¿Tendré problemas entonces? ¿En algún momento me vería obligado a ir a Latin1_General_CI_AS?

No puedo responder! Como las cosas pueden cambiar y siempre es bueno estar en línea con la sugerencia de Microsoft, debe comprender sus datos y las trampas que mencioné anteriormente. Consulte también esto y esto conecta elementos.

Leí que algunos scripts de DBA completan las filas de bases de datos completas, y luego ejecuto el script de inserción en la base de datos con la nueva recopilación.

Cuando desee cambiar la intercalación, estos scripts son útiles. Me he encontrado muchas veces cambiando la intercalación de bases de datos para que coincida con la intercalación del servidor y tengo algunos scripts que lo hacen bastante bien. Hazme saber si lo necesitas.

Referencias

Kin Shah
fuente
5

Además de lo que @Kin detalló en su respuesta , hay algunas cosas más a tener en cuenta al cambiar la intercalación predeterminada del servidor (es decir, la instancia) (los elementos sobre la línea horizontal son directamente relevantes para las dos intercalaciones mencionadas en la Pregunta; elementos debajo de la línea horizontal son relevantes para el general):

  • SI LA COLECCIÓN PREDETERMINADA DE SU BASE DE DATOS NO ESTÁ CAMBIANDO, entonces el problema de rendimiento de "conversión implícita" descrito en la respuesta de @ Kin no debería ser un problema ya que los literales de cadena y las variables locales usan la Clasificación predeterminada de la Base de Datos, no la del servidor. Los únicos impactos para el escenario en el que se cambia la Clasificación de nivel de instancia pero no la Clasificación de nivel de base de datos son (ambos se describen en detalle a continuación):

    • La intercalación potencial entra en conflicto con las tablas temporales (pero no con las variables de la tabla).
    • código roto potencial si la carcasa de variables y / o cursores no coincide con sus declaraciones (pero esto solo puede suceder si se traslada a una instancia con una intercalación binaria o sensible a mayúsculas y minúsculas).
  • Una diferencia entre estas dos intercalaciones es en cómo clasifican ciertos caracteres para los VARCHARdatos (esto no afecta los NVARCHARdatos). Las intercalaciones no EBCDIC SQL_usan lo que se llama "Clasificación de cadenas" para los VARCHARdatos, mientras que todas las demás Colaciones, e incluso los NVARCHARdatos para las SQL_Colaciones no EBCDIC , usan lo que se llama "Clasificación de palabras". La diferencia es que en "Word Sort", el guión -y el apóstrofe '(¿y quizás algunos otros caracteres?) Tienen un peso muy bajo y se ignoran esencialmente a menos que no haya otras diferencias en las cadenas. Para ver este comportamiento en acción, ejecute lo siguiente:

    DECLARE @Test TABLE (Col1 VARCHAR(10) NOT NULL);
    INSERT INTO @Test VALUES ('aa');
    INSERT INTO @Test VALUES ('ac');
    INSERT INTO @Test VALUES ('ah');
    INSERT INTO @Test VALUES ('am');
    INSERT INTO @Test VALUES ('aka');
    INSERT INTO @Test VALUES ('akc');
    INSERT INTO @Test VALUES ('ar');
    INSERT INTO @Test VALUES ('a-f');
    INSERT INTO @Test VALUES ('a_e');
    INSERT INTO @Test VALUES ('a''kb');
    
    SELECT * FROM @Test ORDER BY [Col1] COLLATE SQL_Latin1_General_CP1_CI_AS;
    -- "String Sort" puts all punctuation ahead of letters
    
    SELECT * FROM @Test ORDER BY [Col1] COLLATE Latin1_General_100_CI_AS;
    -- "Word Sort" mostly ignores dash and apostrophe

    Devoluciones:

    String Sort
    -----------
    a'kb
    a-f
    a_e
    aa
    ac
    ah
    aka
    akc
    am
    ar

    y:

    Word Sort
    ---------
    a_e
    aa
    ac
    a-f
    ah
    aka
    a'kb
    akc
    am
    ar

    Si bien "perderá" el comportamiento de "Clasificación de cadenas", no estoy seguro de que pueda llamarlo "característica". Es un comportamiento que se ha considerado indeseable (como lo demuestra el hecho de que no se incluyó en ninguna de las intercalaciones de Windows). Sin embargo, es una diferencia de comportamiento definida entre las dos intercalaciones (de nuevo, solo para VARCHARdatos que no son EBCDIC ), y es posible que tenga un código y / o expectativas del cliente basadas en el comportamiento de "Clasificación de cadenas". Esto requiere probar su código y posiblemente investigar para ver si este cambio en el comportamiento podría tener algún impacto negativo en los usuarios.

  • Otra diferencia entre SQL_Latin1_General_CP1_CI_ASy Latin1_General_100_CI_ASes la capacidad de hacer expansiones en los VARCHARdatos (los NVARCHARdatos ya pueden hacer esto para la mayoría de las SQL_colaciones), como el manejo æcomo si fuera ae:

    IF ('æ' COLLATE SQL_Latin1_General_CP1_CI_AS =
        'ae' COLLATE SQL_Latin1_General_CP1_CI_AS)
    BEGIN
      PRINT 'SQL_Latin1_General_CP1_CI_AS';
    END;
    
    IF ('æ' COLLATE Latin1_General_100_CI_AS =
        'ae' COLLATE Latin1_General_100_CI_AS)
    BEGIN
      PRINT 'Latin1_General_100_CI_AS';
    END;

    Devoluciones:

    Latin1_General_100_CI_AS

    Lo único que está "perdiendo" aquí es no poder hacer estas expansiones. En términos generales, este es otro beneficio de pasar a una Clasificación de Windows. Sin embargo, al igual que con el movimiento "Clasificación de cadenas" a "Clasificación de palabras", se aplica la misma precaución: es una diferencia de comportamiento definitiva entre las dos intercalaciones (de nuevo, solo para VARCHARdatos), y es posible que tenga código y / o cliente expectativas basadas en no tener estas asignaciones. Esto requiere probar su código y posiblemente investigar para ver si este cambio en el comportamiento podría tener algún impacto negativo en los usuarios.

    (Primero observado en esta respuesta SO por @Zarepheth: ¿SQL Server SQL_Latin1_General_CP1_CI_AS se puede convertir de forma segura a Latin1_General_CI_AS? )

  • La intercalación a nivel de servidor se utiliza para establecer la intercalación de las bases de datos del sistema, que incluye [model]. La [model]base de datos se utiliza como plantilla para crear nuevas bases de datos, que incluyen [tempdb]cada vez que se inicia el servidor. Pero, incluso con un cambio de intercalación a nivel de servidor que cambia la intercalación [tempdb], hay una manera algo fácil de corregir las diferencias de intercalación entre la base de datos que está "actual" cuando CREATE #TempTablese ejecuta y [tempdb]. Al crear tablas temporales, declare una intercalación utilizando la COLLATEcláusula y especifique una intercalación de DATABASE_DEFAULT:

    CREATE TABLE #Temp (Col1 NVARCHAR(40) COLLATE DATABASE_DEFAULT);

  • Es mejor usar la versión más reciente de la recopilación deseada, si hay varias versiones disponibles. A partir de SQL Server 2005, se introdujo una serie de colaciones "90", y SQL Server 2008 introdujo una serie de colaciones "100". Puede encontrar estas intercalaciones utilizando las siguientes consultas:

    SELECT * FROM sys.fn_helpcollations() WHERE [name] LIKE N'%[_]90[_]%'; -- 476
    
    SELECT * FROM sys.fn_helpcollations() WHERE [name] LIKE N'%[_]100[_]%'; -- 2686

    Como está en SQL Server 2008 R2, debe usarlo en Latin1_General_100_CI_ASlugar de Latin1_General_CI_AS.

  • Una diferencia entre las versiones sensibles a mayúsculas y minúsculas de estas intercalaciones particulares (es decir, SQL_Latin1_General_CP1_CS_ASy Latin1_General_100_CS_AS) está en el orden de las letras mayúsculas y minúsculas cuando se hace la clasificación sensible a las mayúsculas y minúsculas. Esto también afecta los rangos de clase de un solo carácter (es decir [start-end]) que se pueden usar con el LIKEoperador y la PATINDEXfunción. Las siguientes tres consultas muestran este efecto tanto para la clasificación como para el rango de caracteres .:

    SELECT tmp.col AS [Upper-case first]
    FROM (VALUES ('a'), ('A'), ('b'), ('B'), ('c'), ('C')) tmp(col)
    WHERE tmp.col LIKE '%[A-C]%' COLLATE SQL_Latin1_General_CP1_CS_AS
    ORDER BY tmp.col COLLATE SQL_Latin1_General_CP1_CS_AS; -- Upper-case first
    
    SELECT tmp.col AS [Lower-case first]
    FROM (VALUES ('a'), ('A'), ('b'), ('B'), ('c'), ('C')) tmp(col)
    WHERE tmp.col LIKE '%[A-C]%' COLLATE Latin1_General_100_CS_AS
    ORDER BY tmp.col COLLATE Latin1_General_100_CS_AS; -- Lower-case first
    
    SELECT tmp.col AS [Lower-case first]
    FROM (VALUES (N'a'), (N'A'), (N'b'), (N'B'), (N'c'), (N'C')) tmp(col)
    WHERE tmp.col LIKE N'%[A-C]%' COLLATE SQL_Latin1_General_CP1_CS_AS
    ORDER BY tmp.col COLLATE SQL_Latin1_General_CP1_CS_AS; -- Lower-case first

    La única forma de ordenar las mayúsculas antes de las minúsculas (para la misma letra) es usar una de las 31 intercalaciones que admiten ese comportamiento, que son las Hungarian_Technical_*intercalaciones y un puñado de SQL_intercalaciones (que solo admiten este comportamiento para los VARCHARdatos )

  • Menos importante para este cambio en particular, pero aún así es bueno saberlo, ya que sería impactante si cambiara el servidor a una intercalación binaria o sensible a mayúsculas y minúsculas, es que la intercalación a nivel del servidor también afecta:

    • nombres de variables locales
    • Nombres del CURSOR
    • Etiquetas GOTO
    • resolución de nombre del sysnametipo de datos


    Es decir, si usted o "el programador que se fue recientemente" que aparentemente es responsable de todo el código incorrecto ;-) no tuvo cuidado con la carcasa y declaró una variable, @SomethingIDpero luego se refirió a ella como @somethingIdmás adelante, eso se rompería si pasara a un caso -colación sensible o binaria. Del mismo modo, el código que usa el sysnametipo de datos pero se refiere a él como SYSNAME, SysNameo algo diferente a todas las minúsculas también se romperá si se mueve a una instancia usando una intercalación binaria o sensible a mayúsculas y minúsculas.

Solomon Rutzky
fuente