SQL Server : Différence de calcul du CHECKSUM sur SQL Server 2005 et 2008 ou sur les plateformes 32 bits et 64 bits ?
Ayant eu vent d'une différence de comportement entre version (2005 et 2008) ou entre plateforme de SQL Server (32 bits et 64 bits) de la fonction CHECKSUM, je me suis dit qu'il fallait creuser un peu.
En effet il n'est pas impossible qu'il y ai une telle différence, mais généralement, soit elle est annoncée à l'avance, soit c'est purement et simplement un bug. Il y a déjà des précèdent par exemple le calcul des Hash entre la plateforme x64 et x86 :
string s = "azerty" ;
Console.WriteLine(s.GetHashCode().ToString());
Donne en 32 bits:
765360530
Et en 64 bits:
1423019289
Sur SQL Server, l'équipe de développement essaye de conserver un comportement similaire quelques soit la plateforme, même s'il peut arriver qu'une fonction renvoie des valeurs légèrement différente d'une version ou plateforme à l'autre. Mais ces comportement sont souvent passés à la loupe, car imaginez un Hash Index (http://blogs.codes-sources.com/christian/archive/2009/09/22/sql-server-hash-index-ou-comment-indexer-de-tr-s-grosses-colonnes.aspx) qui se retrouverait avec des valeurs différentes suite à une montée de version ou un changement de serveur lors d'un basculement, il y aurait de quoi s'affoler !
Le calcul du CHECKSUM sur SQL Server se fera par :
SELECT
CHECKSUM('azerty')
Le résultat obtenu est clairement différent de celui .Net, ce qui confirme un algorithme différent.
139376054
A noter une particularité lié au type de données dans le calcul de la fonction précédente. En effet, si je mets ma chaîne en type Unicode (N majuscule précédent celle-ci):
SELECT
CHECKSUM(N'azerty')
On obtient alors un résultat différent :
-1258351920
Passons aux tests sur des versions / plateforme différentes, avec la requête suivant, renvoyant le CHECKSUM, la version et la plateforme (simplifié, je n'ai pas inlus le IA64... je n'ai pas de tels serveurs) :
select
CHECKSUM('azerty'),
SERVERPROPERTY('ProductVersion'),
CASE
WHEN
PATINDEX('%X86%',
@@VERSION)
!=
0 THEN '32 bits'
ELSE
'64 bits'
END
La requête précédente est exécutée sur un ensemble de serveurs équipés de versions et plateformes hétérogènes pour se faire une idée du résultat.
Voici les resulats :
|
CHECKSUM
|
VERSION
|
Plateforme
|
|
139376054
|
10.0.2734.0
|
64 bits
|
|
139376054
|
10.0.2746.0
|
64 bits
|
|
139376054
|
9.00.4266.00
|
64 bits
|
|
139376054
|
10.0.2746.0
|
64 bits
|
|
139376054
|
10.0.2734.0
|
64 bits
|
|
139376054
|
10.0.2734.0
|
64 bits
|
|
139376054
|
10.0.2734.0
|
64 bits
|
|
139376054
|
10.0.2734.0
|
64 bits
|
|
139376054
|
10.0.2746.0
|
64 bits
|
|
139376054
|
10.0.2734.0
|
64 bits
|
|
-1258351920
|
9.00.4220.00
|
32 bits
|
|
139376054
|
10.0.2734.0
|
64 bits
|
|
139376054
|
10.0.2746.0
|
64 bits
|
|
139376054
|
10.0.2746.0
|
64 bits
|
|
139376054
|
10.0.2734.0
|
64 bits
|
|
139376054
|
10.0.2746.0
|
64 bits
|
|
139376054
|
9.00.4207.00
|
32 bits
|
Seule une ligne est différente des autres. On pourrait conclure à une différence de comportement de SQL Server 2005 en 32 bits, mais non. Une autre ligne montre cette même combinaison de version et plateforme avec un résultat identique.
D'où vient alors la différence ? Si vous avez suivi mes 2 exemples en SQL, vous avez vu que le CHECKSUM diffère quand le type de la chaîne change… Or il y a un paramètre qui a une grosse incidence sur çà : Le classement (COLLATE).
Si on ajoute à la liste de notre SELECT :
SERVERPROPERTY('Collation')
On obtient la liste (j'ai ajouté 2 serveurs en plus par rapport à la requête précédente, pour confirmer le comportement,):
|
CHECKSUM
|
Version
|
Plateforme
|
Classement Serveur
|
|
139376054
|
10.0.2734.0
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
139376054
|
9.00.4266.00
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
139376054
|
10.0.2746.0
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
139376054
|
10.0.2746.0
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
139376054
|
10.0.2734.0
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
139376054
|
10.0.2734.0
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
139376054
|
10.0.2746.0
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
-1258351920
|
9.00.4220.00
|
32 bits
|
Latin1_General_CI_AS
|
|
139376054
|
10.0.2734.0
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
139376054
|
10.0.2746.0
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
139376054
|
10.0.2734.0
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
139376054
|
10.0.2734.0
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
139376054
|
10.0.2734.0
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
139376054
|
10.0.2746.0
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
139376054
|
10.0.2746.0
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
139376054
|
10.0.2734.0
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
139376054
|
9.00.4207.00
|
32 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
-1258351920
|
10.0.2734.0
|
64 bits
|
Latin1_General_100_CI_AS
|
|
139376054
|
10.25.9084.0
(SQL Azure)
|
64 bits
|
SQL_Latin1_General_CP1_CI_AS
|
|
-1258351920
|
10.0.2531.0
|
64 bits
|
French_CI_AS
|
|
-1258351920
|
10.50.1352.12
(SQL Server 2008 R2 CTP Nov.)
|
64 bits
|
Latin1_General_100_CI_AS
|
Cette fois ci la différence est flagrante, ce n'est pas de la plateforme ou de la version de SQL Server que dépend le calcul de CHECKSUM, mais du classement courant ! Plus précisément de la différence entre les classements Windows (Latin1_General, Latin1_General_100 et …) et les classements SQL (SQL_Latin1_General_CP1). Le comportement du classement Windows est d'implicitement convertir les constantes de chaîne de caractères en chaîne Unicode.
Pour confirmer ce comportement, et accessoirement déterminer si c'est le classement du serveur ou celui de la base de données qui est pris en compte (et là on croise les doigts pour que ce soit le second, sinon gare aux problèmes dans ses bases de données), on va essayer un autre script :
CREATE
DATABASE x COLLATE Latin1_General_CI_AS
GO
CREATE
DATABASE y COLLATE SQL_Latin1_General_CP1_CI_AS
GO
USE x
GO
SELECT
CHECKSUM('azerty')
GO
USE y
GO
SELECT
CHECKSUM('azerty')
GO
Je vous laisse découvrir le résultat par vous-même. Disons que c'est celui que l'on pouvait espérer dans le meilleur des cas : c'est le classement de la base de données courante qui est pris en considération.
Faites donc très attention à la base de données courante lors des calculs de CHECKSUM. Cependant, la plateforme et la version ne sont pas en cause dans ces formes de calculs... Heureusement j'aurais auguré le pire pour certaines migrations et même backup/restore de certaines applications si tel n'avait pas été le cas.
Bonne somme de contrôle…
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :