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


18

Nous passons de SQL 2005 [Instance et DB ont un classement de SQL_Latin1_General_CP1_CI_AS] à SQL 2008 [qui par défaut est Latin1_General_CI_AS].

J'ai terminé une installation de SQL 2008 R2 et utilisé le Latin1_General_CI_ASclassement par défaut , la restauration de la base de données étant toujours en cours SQL_Latin1_General_CP1_CI_AS. Les problèmes exceptés se sont produits - les tables #temp où se trouvait Latin1_General_CI_ASle db SQL_Latin1_General_CP1_CI_ASet 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 Server 2008 R2, j'ai l'option lors de l' installation à l' utilisation '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 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?


2
Si vous pensez que vous pouvez entrer dans Hekaton dans SQL Server 2014, voici autre chose que vous voudrez peut-être envisager de lire .
Aaron Bertrand

Réponses:


20

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 tels que 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 le 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 COLLATIONPROPERTY

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

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:

entrez la description de l'image ici

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, ce que vous pouvez voir comme 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 sur des colonnes avec des classements différents, vous devez utiliser COLLATEpour comparer les valeurs des colonnes.

TEST 2:

La principale différence est la performance, comme le souligne Erland Sommarskog lors de 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

entrez la description de l'image ici

--- Exécutez les requêtes

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

--- Cela n'aura PAS de conversion IMPLICITE

entrez la description de l'image ici

La raison de la conversion implicite est parce que j'ai mon classement de base de données et de serveur au fur SQL_Latin1_General_CP1_CI_ASet à mesure que la table Table_Latin1_General_CI_AS a des commentaires de colonne 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

entrez la description de l'image ici

- exécuter la requête

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

entrez la description de l'image ici

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 les 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 indiqué dans les tests ci-dessus, lors de la comparaison de données nvarchar avec 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 pourraient 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. Référez-vous également à ceci et à ces éléments de connexion.

J'ai lu que certains scripts 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 quelques scripts qui le font assez bien. Faites-moi savoir si vous en avez besoin.

Les références :


5

En plus de ce que @Kin a détaillé dans sa 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 sous la ligne horizontale sont pertinentes pour le général):

  • SI LA COLLATION PAR DÉFAUT DE VOTRE BASE DE DONNÉES NE CHANGE PAS , le problème de performances de "conversion implicite" décrit dans la réponse de @ Kin ne 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 VARCHARdonnées (cela n'affecte pas les NVARCHARdonnées). Les SQL_classements non EBCDIC utilisent ce qu'on appelle le "tri par chaîne" pour les VARCHARdonnées, tandis que tous les autres classements, et même les NVARCHARdonnées pour les SQL_classements non EBCDIC , utilisent ce que l'on appelle le "tri par mots". 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 sauf s'il n'y a pas 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

    Alors que vous "perdrez" le comportement "Tri de chaînes", 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, il s'agit d' une nette différence de comportement entre les deux classements (là encore, uniquement pour les VARCHARdonnées non EBCDIC ), et vous pouvez avoir du code et / ou des attentes des clients en fonction du comportement "String Sort". Cela nécessite de tester votre code et éventuellement de rechercher pour voir si ce changement de comportement pourrait avoir un impact négatif sur les utilisateurs.

  • Une autre différence entre SQL_Latin1_General_CP1_CI_ASet Latin1_General_100_CI_ASest la possibilité de faire des extensions sur les VARCHARdonnées (les NVARCHARdonnées peuvent déjà les faire pour la plupart des SQL_classements), comme la manipulation æcomme si c'était le cas 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 n'est pas en mesure de 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 VARCHARdonnées), et vous pouvez avoir du code et / ou un client attentes basées sur l' absence de ces mappages. Cela nécessite de tester votre code et éventuellement de rechercher pour voir si ce changement de comportement pourrait avoir un impact négatif sur les utilisateurs.

    (noté pour la première fois dans cette réponse SO 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]. La [model]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 qui change 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" lorsqu'elle CREATE #TempTableest exécutée et [tempdb]. Lors de la création de tables temporaires, déclarez un classement à l'aide de la COLLATEclause 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 à la Latin1_General_100_CI_ASplace de Latin1_General_CI_AS.

  • Une différence entre les versions sensibles à la casse de ces classements particuliers (c'est-à SQL_Latin1_General_CP1_CS_AS- dire 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 à un caractère (c'est-à-dire [start-end]) qui peuvent être utilisées avec l' LIKEopérateur et la PATINDEXfonction. 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 sont les Hungarian_Technical_*classements et une poignée de SQL_classements (qui ne prennent en charge ce comportement que pour les VARCHARdonnées ).

  • 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 sysnametype de données


    Ce qui signifie que si vous ou "le programmeur qui est parti récemment" qui est apparemment responsable de tout mauvais code ;-) ne faisaient pas attention à la casse et déclaraient une variable comme @SomethingIDmais y faisaient référence plus @somethingIdtard, cela se briserait si vous passez à un cas -classement sensible ou binaire. De même, le code qui utilise le sysnametype de données mais y fait référence sous le nom de SYSNAME, SysNameou autre chose que tout en minuscules se cassera également s'il est déplacé vers une instance à l'aide d'un classement sensible à la casse ou binaire.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.