LATCH_EX attend la ressource METADATA_SEQUENCE_GENERATOR

11

Nous avons un processus qui génère un rapport d'inventaire. Côté client, le processus fractionne un nombre configurable de threads de travail pour créer un bloc de données pour le rapport qui correspond à un magasin sur plusieurs (potentiellement des milliers, généralement des dizaines). Chaque thread de travail appelle un service Web qui exécute une procédure stockée.

Le processus de base de données pour le traitement de chaque bloc rassemble un tas de données dans une table #Temporary. À la fin de chaque bloc de traitement, les données sont écrites dans une table permanente dans tempdb. Enfin, à la fin du processus, un thread côté client demande toutes les données de la table tempdb permanente.

Plus il y a d'utilisateurs qui exécutent ce rapport, plus il ralentit. 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é du processus. Tous ces SPID avaient de l'ordre de 50 ms d'attente de type LATCH_EXsur ressource METADATA_SEQUENCE_GENERATOR (00000010E13CA1A8). Un SPID a cette ressource, et tous les autres bloquent. Je n'ai rien trouvé sur cette ressource d'attente lors d'une recherche sur le Web.

La table dans tempdb que nous utilisons a une IDENTITY(1,1)colonne. Ces SPID attendent-ils la colonne IDENTITY? Quelles méthodes pourrions-nous utiliser pour réduire ou éliminer le blocage?

Le serveur fait partie d'un cluster. Le serveur exécute SQL Server 2012 Standard Edition SP1 64 bits sur Windows 2008 R2 Enterprise 64 bits. Le serveur a 64 Go de RAM et 48 processeurs, mais la base de données ne peut en utiliser que 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 conserver toutes ces données. Changer cela serait un défi technique et politique intéressant, mais je suis ouvert aux suggestions.)

MISE À JOUR 23/04/2013

Nous avons ouvert un dossier d'assistance avec Microsoft. Je garderai cette question à jour à mesure que nous en apprendrons davantage.

MISE À JOUR 5/10/2013

L'ingénieur de support SQL Server a convenu que les attentes étaient causées par la colonne IDENTITY. La suppression de l'IDENTITÉ a éliminé les attentes. Nous n'avons pas pu dupliquer le problème sur SQL 2008 R2; cela s'est produit uniquement sur SQL 2012.

Paul Williams
la source
Le processus copie-t-il essentiellement les données des tables #Temporary vers la table permanente, ou y a-t-il une logique de transformation supplémentaire à cette étape?
Jon Seigel
À l'étape qu'il attend, il copie les enregistrements d'inventaire d'un seul magasin dans la table permanente sans transformation. Nous pourrions fonctionner à l'intérieur de la table permanente tout le temps, mais je pense que le programmeur a choisi d'utiliser une table #Temporary comme zone d'attente pour empêcher les mises à jour fréquentes des données de se convertir en verrous PAGE.
Paul Williams

Réponses:

4

En supposant que vous pouvez isoler le problème de la génération de valeurs d'identité (essayez de supprimer cette colonne en tant que test), je recommanderais ceci:

  1. Supprimez la IDENTITYpropriété de la colonne du tableau final.
  2. Générez des valeurs d'identité dans chacune des tables #Temporary.
  3. Lors du chargement de la table finale, combinez un identifiant numérique pour le magasin particulier avec les valeurs d'identité de l'étape 2.

Donc, si vous avez des identifiants de magasin 3 et 4, vous vous retrouveriez avec des valeurs finales d'ID comme ceci:

3000000001
3000000002
3000000003
...
4000000001
4000000002
...

Ou quelque chose de similaire à ça. Vous avez eu l'idée.

Cela éliminera le besoin de sérialiser la IDENTITYgénération tout en préservant l'unicité du résultat final.

Alternativement, selon la façon dont le processus fonctionne, insérez les valeurs finales d'ID calculées dans les tables #Temporary. Ensuite, vous pouvez créer une vue qui UNION ALLles regroupe, éliminant ainsi la nécessité de copier les données.

Jon Seigel
la source
Merci pour votre réponse. Je suis d'accord si tel est le problème, l'utilisation d'une clé fabriquée (ou pas de clé du tout) pourrait le résoudre. Nous avons ouvert un dossier avec Microsoft concernant ce problème. Je posterai le résultat ici et accepterai votre réponse s'ils conviennent que c'est le problème.
Paul Williams
@Paul: Veuillez me le faire savoir; Je suis tout aussi curieux. Comme vous, je n'ai rien trouvé sur le Web à propos de ce verrou, mais il est certainement raisonnable que ce soit la sérialisation de l'identité / séquence. Que ce soit ou non le goulot d'étranglement est difficile à dire, mais avec plus de 30 threads en compétition pour les valeurs, cela semble probable. Vous pouvez également essayer de copier à partir de chaque table #Temporary en série (au lieu de parallèle) pour voir si cela aide.
Jon Seigel
2
L'ingénieur SQL Server a convenu qu'il s'agissait probablement de la IDENTITYcolonne. Nous l'avons retiré de l'index cluster déjà large et supprimé complètement la colonne. Ce n'était pas nécessaire. Par la suite, ces attentes LATCH_EX ont disparu. Nous n'avons pas pu dupliquer les attentes sur SQL 2008 R2. Le problème ne s'est produit que sur SQL Server 2012.
Paul Williams
@ Paul: Merci pour le suivi. Très intéressant. Je suppose que le code qui génère des IDENTITYvaleurs a été réécrit pour utiliser le nouveau truc de génération de séquence qui était nouveau en 2012. Sur <2012, vous pouvez voir un type de verrou différent, bien que s'il n'y avait pas de problème de performance, il semble qu'il y en ait eu une régression dans le code. Dans tous les cas, la suppression de la IDENTITYcolonne est la chose la plus sûre.
Jon Seigel
Au lieu de l'identité, vous pouvez essayer d'utiliser une «SEQUENCE» (ce qui est nouveau dans SQL 2012)
Bogdan Maxim
7

(Mise à jour février 2019)

Ceci est un vieux post, qui a dit que j'ai finalement réussi à convaincre Microsoft que le fait même que cela se produise est en effet un défaut.

Mise à jour: MS a confirmé le défaut et lui a attribué un bogue n ° 12628722.

J'avais vu ce message en novembre 2018 lorsque nous avons commencé à souffrir à peu près la même chose après la mise à niveau de Sql Server 2005 vers Sql Server 2017. Une table de 3,3 millions de lignes qui prenait 10 secondes pour l'insertion en vrac a soudainement commencé à prendre 10 minutes sur des tables avec des Identitycolonnes.

Il s'avère qu'il y a deux problèmes derrière cela:

  1. Microsoft a modifié le comportement dans Sql Server 2014 pour forcer les insertions en bloc à s'exécuter en parallèle - dans les versions précédentes, les insertions en bloc recevaient un plan sérialisé.
  2. Une fois exécuté en parallèle sur notre boîtier à 32 cœurs, le moteur a passé plus de temps avec les cœurs à se verrouiller les uns aux autres qu'à faire le travail.

Cela m'a pris 4 semaines mais juste après les vacances, j'ai reçu un cadeau tardif du Père Noël - confirmation que le problème était effectivement un défaut.

Il existe quelques solutions possibles que nous avons trouvées jusqu'à ce que cela soit résolu:

  1. À utiliser Option (MaxDop 1)dans la requête pour reconvertir l'insertion en bloc en un plan sérialisé.
  2. Masquez la colonne Identité en la coulant (par exemple Select Cast(MyIdentityColumn As Integer) As MyIdentityColumn)
    • cela empêche la copie de la propriété d'identité lors de l'utilisation SELECT...INTO
  3. Supprimez la colonne d'identité comme décrit ci-dessus.
  4. Modifiez le mode de compatibilité de la base de données sur Sql Server 2012 ou une version antérieure pour rétablir un plan sérialisé.

Mise à jour: Le correctif que MS implémentera consistera à renvoyer ces types d'insertions à l'aide d'un Serialized plan. Ceci est prévu pour Sql Server 2017 CU14 (pas de nouvelles sur les autres versions de Sql Server - désolé!). Une fois implémenté, Trace Flag 9492 devra être activé, soit au niveau du serveur, soit via DBCC TraceOn .

Rachel Ambler
la source