web-dev-qa-db-fra.com

Passer de SQL 2005 [SQL_Latin1_General_CP1_CI_AS] à 2008 - vais-je perdre toutes les fonctionnalités en utilisant la «compatibilité descendante»

Nous passons de SQL 2005 [L'instance et la base de données ont un classement de SQL_Latin1_General_CP1_CI_AS] à SQL 2008 [par défaut à Latin1_General_CI_AS].

J'ai terminé une installation de SQL 2008 R2 et j'ai utilisé par défaut Latin1_General_CI_AS collation, avec la restauration de la base de données toujours sur SQL_Latin1_General_CP1_CI_AS. Les problèmes exceptés se sont produits - les tables #temp où dans Latin1_General_CI_AS alors que la base de données était en SQL_Latin1_General_CP1_CI_AS et c'est là que je suis maintenant - j'ai besoin de conseils sur les pièges maintenant s'il vous plaît.

Lors de l'installation de SQL 2008 R2, j'ai la possibilité lors de l'installation d'utiliser 'SQL Collation, used for backwards compatibility' où j'ai la possibilité de sélectionner le même classement que la base de données 2005: SQL_Latin1_General_CP1_CI_AS.

  1. Cela me permettra de ne pas avoir de problèmes avec les tables #temp, mais y a-t-il des pièges?

  2. Aurais-je perdu des fonctionnalités ou des fonctionnalités de toute nature en n'utilisant pas un classement "actuel" de SQL 2008?

  3. Qu'en est-il lorsque nous passons (par exemple dans 2 ans) de 2008 à SQL 2012? Vais-je avoir des problèmes alors?
  4. Serais-je obligé à un moment donné d'aller à Latin1_General_CI_AS?

  5. J'ai lu que certains scripts de DBA complètent les lignes de bases de données complètes, puis exécutez le script d'insertion dans la base de données avec le nouveau classement - j'ai très peur et méfiez-vous de cela - recommanderiez-vous de faire cela?

18
Peter PitLock

Tout d'abord, des excuses pour une réponse aussi longue, car je pense qu'il y a toujours beaucoup de confusion lorsque les gens parlent de termes comme le classement, l'ordre de tri, la page de code, etc.

De BOL :

Les classements dans SQL Server fournissent des règles de tri, des casse et des propriétés de sensibilité d'accent pour vos données . Les classements utilisés avec les types de données de caractères tels que char et varchar dictent la page de codes et les caractères correspondants qui peuvent être représentés pour ce type de données. Que vous installiez une nouvelle instance de SQL Server, restauriez une sauvegarde de base de données ou connectiez un serveur à des bases de données clientes, il est important que vous compreniez les exigences locales, l'ordre de tri et la sensibilité à la casse et à l'accentuation des données avec lesquelles vous travaillerez. .

Cela signifie que le classement est très important car il spécifie des règles sur la façon dont les chaînes de caractères des données sont triées et comparées.

Remarque: Plus d'informations sur PROPRIÉTÉ DE COLLATION

Maintenant, comprenons d'abord les différences ......

Fonctionnant sous 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

Les résultats seraient:

enter image description here

En regardant les résultats ci-dessus, la seule différence est l'ordre de tri entre les 2 classements, mais ce n'est pas vrai, comme vous pouvez le voir ci-dessous:

Test 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

Résultats du test 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.

D'après les résultats ci-dessus, nous pouvons voir que nous ne pouvons pas comparer directement les valeurs des colonnes avec différents classements, vous devez utiliser COLLATE pour comparer les valeurs des colonnes.

TEST 2:

La principale différence est la performance, comme le souligne Erland Sommarskog à cette discussion sur 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')

--- Créer des index sur les deux tables

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)

--- Exécutez les requêtes

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

--- Cela aura une conversion IMPLICITE

enter image description here

--- Exécutez les requêtes

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

--- Ceci [~ # ~] ne sera pas [~ # ~] avec conversion IMPLICITE

enter image description here

La raison de la conversion implicite est parce que ma collation de base de données et de serveur est à la fois SQL_Latin1_General_CP1_CI_AS Et que la table Table_Latin1_General_CI_AS a une colonne Commentaires définis comme VARCHAR(50) avec COLLATE Latin1_General_CI_AS , donc pendant la recherche SQL Server doit effectuer une conversion IMPLICIT.

Test 3:

Avec la même configuration, nous allons maintenant comparer les colonnes varchar avec les valeurs nvarchar pour voir les changements dans les plans d'exécution.

- exécuter la requête

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

enter image description here

- exécuter la requête

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

enter image description here

Notez que la première requête peut effectuer une recherche d'index mais doit effectuer une conversion implicite tandis que la seconde effectue une analyse d'index qui s'avère inefficace en termes de performances lorsqu'elle analysera de grandes tables.

Conclusion:

  • Tous les tests ci-dessus montrent qu'il est très important d'avoir un bon classement pour votre instance de serveur de base de données.
  • SQL_Latin1_General_CP1_CI_AS Est un classement SQL avec des règles qui vous permettent de trier les données pour unicode et non-unicode sont différentes.
  • Le classement SQL ne pourra pas utiliser Index lors de la comparaison de données unicode et non-unicode, comme vu dans les tests ci-dessus, lors de la comparaison de données nvarchar à des données varchar, il analyse Index et ne recherche pas.
  • Latin1_General_CI_AS Est un classement Windows avec les règles qui vous permettent de trier les données pour unicode et non-unicode sont les mêmes.
  • Le classement Windows peut toujours utiliser Index (recherche d'index dans l'exemple ci-dessus) lors de la comparaison de données unicode et non unicode, mais vous voyez une légère baisse des performances.
  • Je recommande vivement de lire la réponse d'Erland Sommarskog + les éléments de connexion qu'il a pointés.

Cela me permettra de ne pas avoir de problèmes avec les tables #temp, mais y a-t-il des pièges?

Voir ma réponse ci-dessus.

Aurais-je perdu des fonctionnalités ou des fonctionnalités de toute nature en n'utilisant pas un classement "actuel" de SQL 2008?

Tout dépend des fonctionnalités/fonctionnalités auxquelles vous faites référence. Le classement consiste à stocker et à trier des données.

Qu'en est-il lorsque nous passons (par exemple dans 2 ans) de 2008 à SQL 2012? Vais-je avoir des problèmes alors? Serais-je obligé à un moment donné d'aller à Latin1_General_CI_AS?

Je ne peux pas me porter garant! Comme les choses peuvent changer et qu'il est toujours bon d'être en accord avec la suggestion de Microsoft +, vous devez comprendre vos données et les pièges que j'ai mentionnés ci-dessus. Reportez-vous également à this et this connectez les éléments.

J'ai lu que certains scripts de DBA complètent les lignes de bases de données complètes, puis exécutez le script d'insertion dans la base de données avec le nouveau classement - j'ai très peur et méfiez-vous de cela - recommanderiez-vous de faire cela?

Lorsque vous souhaitez modifier le classement, ces scripts sont utiles. Je me suis retrouvé à changer le classement des bases de données pour correspondre au classement du serveur plusieurs fois et j'ai des scripts qui le font assez bien. Faites-moi savoir si vous en avez besoin.

Références :

20
Kin Shah

En plus de ce que @Kin a détaillé dans son réponse , il y a quelques autres choses à savoir lors du changement du classement par défaut du serveur (c'est-à-dire de l'instance) (les éléments au-dessus de la ligne horizontale sont directement pertinents pour les deux classements mentionnés dans la question; les éléments situés sous la ligne horizontale sont pertinents pour le général):

  • SI LA COLLATION PAR DÉFAUT DE VOTRE BASE DE DONNÉES IS [~ # ~] pas [~ # ~] CHANGING, alors le problème de performance de "conversion implicite" décrit dans la réponse de @ Kin devrait pas être un problème car les littéraux de chaîne et les variables locales utilisent le classement par défaut de la base de données, pas celui du serveur. Les seuls impacts pour le scénario dans lequel le classement au niveau de l'instance est modifié mais pas le classement au niveau de la base de données sont (tous deux décrits en détail ci-dessous):

    • conflits de classement potentiels avec des tables temporaires (mais pas avec des variables de table).
    • code cassé potentiel si la casse des variables et/ou des curseurs ne correspond pas à leurs déclarations (mais cela ne peut se produire que si vous passez à une instance avec un classement binaire ou sensible à la casse).
  • Une différence entre ces deux classements réside dans la façon dont ils trient certains caractères pour les données VARCHAR (cela n'affecte pas les données NVARCHAR). Le non-EBCDIC SQL_ Les classements utilisent ce qu'on appelle le "tri par chaîne" pour les données VARCHAR, tandis que tous les autres classements, et même les données NVARCHAR pour les données non EBCDIC SQL_ Collations, utilisez ce qu'on appelle le "Tri par mot". La différence est que dans "Tri Word", le tiret - et l'apostrophe ' (et peut-être quelques autres caractères?) reçoivent un poids très faible et sont essentiellement ignorés à moins qu'il n'y ait d'autres différences dans les chaînes. Pour voir ce comportement en action, exécutez ce qui suit:

    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
    

    Retour:

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

    et:

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

    Bien que vous "perdiez" le comportement "Tri par chaîne", je ne suis pas sûr d'appeler cela une "fonctionnalité". C'est un comportement qui a été jugé indésirable (comme en témoigne le fait qu'il n'a été présenté dans aucun des classements Windows). Cependant, c'est est une nette différence de comportement entre les deux classements (là encore, juste pour les données non EBCDIC VARCHAR), et vous pourriez avoir du code et/ou des attentes des clients en fonction sur le comportement "String Sort". Cela nécessite de tester votre code et éventuellement de rechercher si ce changement de comportement pourrait avoir un impact négatif sur les utilisateurs.

  • Une autre différence entre SQL_Latin1_General_CP1_CI_AS et Latin1_General_100_CI_AS est la possibilité de faire Expansions sur VARCHAR data (NVARCHAR data peut déjà faire cela pour la plupart SQL_ Collations), telles que la gestion æ comme si c'était 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;
    

    Retour:

    Latin1_General_100_CI_AS
    

    La seule chose que vous "perdez" ici est pas pouvoir faire ces extensions. De manière générale, il s'agit d'un autre avantage du passage à un classement Windows. Cependant, tout comme avec le déplacement "String Sort" vers "Word Sort", la même prudence s'applique: il s'agit d'une nette différence de comportement entre les deux classements (là encore, juste pour les données VARCHAR), et vous pourriez avoir du code et/ou des attentes des clients basés sur pas ayant ces mappages Cela nécessite de tester votre code et éventuellement de rechercher si ce changement de comportement pourrait avoir un impact négatif sur les utilisateurs.

    (noté pour la première fois dans cette réponse S.O. par @Zarepheth: SQL Server SQL_Latin1_General_CP1_CI_AS peut-il être converti en toute sécurité en Latin1_General_CI_AS? )

  • Le classement au niveau du serveur est utilisé pour définir le classement des bases de données système, qui comprend [model]. Le [model] la base de données est utilisée comme modèle pour créer de nouvelles bases de données, ce qui inclut [tempdb] à chaque démarrage du serveur. Mais, même avec un changement de classement au niveau du serveur, changer le classement de [tempdb], il existe un moyen assez simple de corriger les différences de classement entre la base de données qui est "actuelle" lorsque CREATE #TempTable est exécuté et [tempdb]. Lors de la création de tables temporaires, déclarez un classement à l'aide de la clause COLLATE et spécifiez un classement de DATABASE_DEFAULT:

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

  • Il est préférable d'utiliser la version la plus récente du classement souhaité, si plusieurs versions sont disponibles. À partir de SQL Server 2005, une série de classements "90" a été introduite et SQL Server 2008 a introduit une série de classements "100". Vous pouvez trouver ces classements à l'aide des requêtes suivantes:

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

    Étant donné que vous utilisez SQL Server 2008 R2, vous devez utiliser Latin1_General_100_CI_AS au lieu de Latin1_General_CI_AS.

  • Une différence entre les versions sensibles à la casse de ces classements particuliers (c'est-à-dire SQL_Latin1_General_CP1_CS_AS et Latin1_General_100_CS_AS) est dans l'ordre des lettres majuscules et minuscules lors du tri sensible à la casse. Cela affecte également les plages de classes à caractère unique (c'est-à-dire [start-end]) utilisable avec l'opérateur LIKE et la fonction PATINDEX. Les trois requêtes suivantes montrent cet effet pour le tri et la plage de caractères:

    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 seule façon d'obtenir le tri en majuscules avant les minuscules (pour la même lettre) consiste à utiliser l'un des 31 classements prenant en charge ce comportement, qui est le Hungarian_Technical_* Collations et une poignée de SQL_ Collations (qui ne prennent en charge ce comportement que pour les données VARCHAR).

  • Moins important pour ce changement particulier, mais toujours bon à savoir car cela aurait un impact si vous changez le serveur en un classement binaire ou sensible à la casse, c'est que le classement au niveau du serveur affecte également:

    • noms de variables locales
    • Noms du CURSEUR
    • Étiquettes GOTO
    • résolution de nom du type de données sysname


    Cela signifie que si vous ou "le programmeur qui a quitté récemment" qui est apparemment responsable de tout mauvais code ;-) n'ont pas fait attention à la casse et ont déclaré une variable comme @SomethingID mais l'a ensuite appelé @somethingId plus tard, cela se briserait en cas de passage à un classement sensible à la casse ou binaire. De même, le code qui utilise le type de données sysname mais y fait référence en tant que SYSNAME, SysName, ou autre chose que tout en minuscule se brisera également s'il est déplacé vers une instance à l'aide d'un collation sensible à la casse ou binaire.

5
Solomon Rutzky