Symptômes
Lorsque vous utilisez SCOPE_IDENTITY() ou @@IDENTITYpour récupérer les valeurs insérées dans une colonne d'identité, vous remarquerez peut-être que ces fonctions retournent parfois des valeurs incorrectes. Le problème se produit uniquement lorsque vos requêtes utilisent des plans d'exécution parallèles. Pour plus d'informations sur la manière de déterminer si vos requêtes vont utiliser des plans d'exécution parallèles, reportez-vous à la section Parallèle de requête intra-requête de l'article technique suivant sur Téléchargements Microsoft :
Cause
Microsoft a confirmé l’existence de ce problème dans les produits Microsoft répertoriés au début de cet article.
Résolution
Informations sur les mises à jour cumulatives
SQL Server 2008 R2 Service Pack 1
Le correctif pour résoudre ce problème a été publié dans la mise à jour cumulative 5 SQL Server 2008 R2 Service Pack 1. Pour plus d'informations sur l'obtention de ce package de mise à jour cumulative, cliquez sur le numéro d'article suivant pour afficher cet article dans la Base de connaissances Microsoft :
2659694Package de mise à jour cumulative 5 SQL Server 2008 R2 Service Pack 1
RemarqueÉtant donné que les builds sont cumulatives, chaque nouvelle version de correctif contient tous les correctifs et tous les correctifs de sécurité inclus dans la version précédente du correctif SQL Server 2008 R2. Nous vous recommandons d'appliquer la version de correctif la plus récente contenant ce correctif. Pour plus d'informations, cliquez sur le numéro ci-dessous pour afficher l'article correspondant dans la Base de connaissances Microsoft :
2567616Les SQL Server 2008 R2 publiées après SQL Server 2008 R2 Service Pack 1
Solution de contournement
Microsoft recommande de ne pas utiliser l'une de ces fonctions dans vos requêtes lorsque des plans parallèles sont impliqués, car ils ne sont pas toujours fiables. À la place, utilisez la clause OUTPUT de l'instruction INSERT pour récupérer la valeur d'identité, comme illustré dans l'exemple ci-dessous.
Exemple d'utilisation de la clause OUTPUT :
DECLARE @MyNewIdentityValues table(myidvalues int)
déclarer @A table (ID int primary key)
insérer dans @A de valeurs (1)
déclarer @B table (ID int primary key identity(1,1), B int not null)
insérer dans @B de valeurs (1)
sélectionnez
[RowCount] = @@RowCount,
[@@IDENTITY] = @@IDENTITY,
[SCOPE_IDENTITY] = SCOPE_IDENTITY()
définir le profil de statistique sur
insérer dans _ddr_T
sortie inserted.ID dans @MyNewIdentityValues
sélectionnez
b.ID
à partir @A
joint @B gauche sur b.ID = 1
participer à gauche @B b2 sur b2. B = -1
left join _ddr_T t on t.T = -1
s'il n'existe pas (sélectionnez * _ddr_T t2 où t2.ID = -1)
Définir le profil statistique off
sélectionnez
[RowCount] = @@RowCount,
[@@IDENTITY] = @@IDENTITY,
[SCOPE_IDENTITY] = SCOPE_IDENTITY(),
[IDENT_CURRENT] = IDENT_CURRENT('_ddr_T')
sélectionnez * dans @MyNewIdentityValues
go
Si votre situation nécessite que vous devrez utiliser l'une de ces fonctions, vous pouvez utiliser l'une des méthodes suivantes pour contourner le problème.
Méthode 1 :
Inclure l'option suivante dans votre requête
OPTION (MAXDOP 1)
Remarque: cela peut nuire aux performances de la partie SELECT de votre requête.
Méthode 2 :
Lisez la valeur de la partie SELECT dans un ensemble de variables (ou une seule variable de table), puis insérez-la dans la table cible avec MAXDOP=1. Étant donné que le plan INSERT n'est pas parallèle, vous obtenez la bonne sémantique, mais votre select sera parallèle pour obtenir les performances souhaitées.
Méthode 3 :
Exécutez l'instruction suivante pour définir l'option max de degré d'parallèle sur 1 :
sp_configure 'degrés max d'parallèle', 1
go
Reconfigurer avec remplacement
go
Remarque: cette méthode peut entraîner une dégradation des performances sur le serveur. Vous ne devez utiliser cette méthode que si vous l'avez évaluée dans un environnement de test ou intermédiaire.