Nous avons un processus qui génère un rapport d'inventaire. Du côté du client, le processus se divise d'un nombre configurable de threads de travailleurs pour créer un morceau de données pour le rapport qui correspond à un magasin de plusieurs (potentiellement des milliers, des dizaines typiquement). Chaque fil de travail appelle un service Web qui exécute une procédure stockée.
Le processus de base de données de traitement de chaque morceau recueille un tas de données dans une table #Temporary. À la fin de chaque morceau de traitement, les données sont écrites sur une table permanente dans TEMPDB. Enfin, à la fin du processus, un fil du côté client demande toutes les données de la table permanente TEMPDB.
Plus il y a plus d'utilisateurs qui gèrent ce rapport, plus il est lent. J'ai analysé l'activité dans la base de données. À un moment donné, j'ai vu 35 demandes distinctes toutes bloquées à un moment donné dans le processus. Tous ces spids ont eu sur l'ordre de 50 ms attend de type LATCH_EX
Sur la ressource METADATA_SEQUENCE_GENERATOR (00000010E13CA1A8)
. Une SPID a cette ressource et tous les autres bloquent. Je n'ai rien trouvé sur cette ressource d'attente sur une recherche sur le Web.
La table dans TEMPDB que nous utilisons a une colonne IDENTITY(1,1)
. Ces spids attendent-ils la colonne d'identité? Quelles méthodes pourrions-nous utiliser pour réduire ou éliminer le blocage?
Le serveur fait partie d'un cluster. Le serveur exécute 64 bits SQL Server 2012 Standard Standard SP1 sur Windows 2008 R2 Enterprise 64 bits. Le serveur a 64 gb RAM et 48 processeurs, mais la base de données ne peut qu'utiliser 16 car il s'agit de l'édition standard.
(Notez que je ne suis pas ravi de la conception d'utiliser une table permanente dans TEMPDB pour contenir toutes ces données. Changer ce serait un défi technique et politique intéressant, mais je suis ouvert aux suggestions.)
Mise à jour 4/23/201
Nous avons ouvert un cas de support avec Microsoft. Je tiendrai cette question à jour comme nous en apprenons plus.
Mise à jour 5/10/201
L'ingénieur de support SQL Server a convenu que les attentes ont été causées par la colonne d'identité. Supprimer l'identité éliminé les attentes. Nous ne pouvions pas dupliquer la question sur SQL 2008 R2; Cela ne s'est produit que sur SQL 2012.
En supposant que vous puissiez isoler le problème à la génération de valeurs d'identité (essayez de supprimer cette colonne comme test), ce que je recommanderais est-ce:
IDENTITY
de la colonne de la table finale.Donc, si vous avez des identifiants de stockage 3 et 4, vous vous retrouveriez avec des valeurs d'identification finales comme celle-ci:
3000000001
3000000002
3000000003
...
4000000001
4000000002
...
Ou quelque chose de similaire à celui-là. Vous avez eu l'idée.
Cela éliminera la nécessité de sérialiser sur IDENTITY
génération tout en préservant l'unicité dans le résultat final.
Selon la manière dont le processus fonctionne, insérez les valeurs d'identification calculées finales dans les tables #Temporary. Ensuite, vous pouvez créer une vue que UNION ALL
s les ensemble, éliminant la nécessité de copier les données du tout.
(Mise à jour février 2019)
C'est un ancien poste qui a dit que j'ai finalement réussi à convaincre Microsoft que ce fait que cela se produit est effectivement un défaut.
-(( Mise à jour: MS a confirmé le défaut et l'a attribué un numéro de bogue de 12628722.
J'avais vu ce poste au cours du dernier novembre 2018 lorsque nous avons commencé à souffrir de la même chose après notre mise à niveau de SQL Server 2005 à SQL Server 2017. Une table de 3,3 millions de lignes qui prenait 10 secondes à l'insert en vrac a soudainement commencé à prendre 10 minutes sur des tables avec Identity
colonnes.
S'avère qu'il y a deux problèmes derrière cela:
Cela m'a pris 4 semaines, mais juste après les vacances, j'ai eu un cadeau tardif de Santa - Confirmation selon laquelle la question était en effet un défaut.
Il y a quelques solutions de contournement possibles que nous avons trouvées jusqu'à ce que cela soit corrigé:
Option (MaxDop 1)
dans la requête pour revenir à l'insertion en vrac dans un plan sérialisé.Select Cast(MyIdentityColumn As Integer) As MyIdentityColumn
) SELECT...INTO
(( mise à jour: La MS Fix sera mise en œuvre pour renvoyer ces sortes d'insertions Retour à l'aide d'un Serialized
Plan. Ceci est prévu pour SQL Server 2017 CU14 (aucune nouvelle sur d'autres versions de SQL Server - Désolé!). Lors de la mise en œuvre, le drapeau de trace 9492 devra être activé, soit au niveau du serveur, soit via DBCC TraceOn
.