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
.
Cela me permettra de ne pas avoir de problèmes avec les tables #temp, mais y a-t-il des pièges?
Aurais-je perdu des fonctionnalités ou des fonctionnalités de toute nature en n'utilisant pas un classement "actuel" de SQL 2008?
Serais-je obligé à un moment donné d'aller à Latin1_General_CI_AS
?
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?
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:
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
--- 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
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
- exécuter la requête
DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_SQL_Latin1_General_CP1_CI_AS WHERE Comments = N'kin_test1'
GO
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:
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.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.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 :
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):
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:
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.