Cause d'un processus victime d'une impasse

105

J'ai un processus avec un Select qui prend beaucoup de temps à se terminer, de l'ordre de 5 à 10 minutes.
Je n'utilise actuellement pas NOLOCK comme indice pour le moteur de base de données MS SQL.
En même temps, nous avons un autre processus effectuant des mises à jour et des insertions dans la même base de données et les mêmes tables.
Le premier processus a commencé, récemment pour se terminer prématurément avec un message

SQLEXCEPTION: La transaction a été bloquée sur les ressources de verrouillage avec un autre processus et a été choisie comme victime du blocage.

Ce premier processus s'exécute sur d'autres sites dans des conditions identiques mais avec des bases de données plus petites et donc l'instruction de sélection en question prend un laps de temps beaucoup plus court (de l'ordre de 30 secondes environ). Dans ces autres sites, je ne reçois pas le message de blocage dans ces autres sites. Je n'ai pas non plus reçu ce message sur le site qui rencontre le problème au départ, mais, je suppose, à mesure que la base de données s'est agrandie, je pense que j'ai dû franchir un certain seuil. Voici mes questions:

  1. Le temps nécessaire à l'exécution d'une transaction pourrait-il rendre le processus associé plus susceptible d'être signalé comme victime d'un blocage.
  2. Si j'exécute la sélection avec un indice NOLOCK, est-ce que cela résoudra le problème?
  3. Je soupçonne qu'un champ datetime qui est vérifié dans le cadre de la clause WHERE dans l'instruction select provoque le temps de recherche lent. Puis-je créer un index basé sur ce champ? Est-ce conseillé?
Elliott
la source
Réponse partielle au point 1: ne pas confondre un blocage avec un timeout. Si vous subissez un délai d'expiration, le temps nécessaire à la fin d'une transaction peut être responsable de la fin de l'autre. De plus, il serait utile de savoir sur quelle ressource vous vous bloquez (s'agit-il d'un index ou d'une table?).
NealB
1
SET DEADLOCK_PRIORITY HIGH ALTER DATABASE dbname SET MULTI_USER;
gstackoverflow

Réponses:

128

Q1: Le temps nécessaire à l'exécution d'une transaction pourrait-il rendre le processus associé plus susceptible d'être signalé comme victime d'un blocage.

Non. Le SELECT est la victime car il n'avait lu que des données, donc la transaction a un coût moins élevé qui lui est associé, elle est donc choisie comme victime:

Par défaut, le moteur de base de données choisit comme victime de blocage la session exécutant la transaction dont la restauration est la moins coûteuse . Un utilisateur peut également spécifier la priorité des sessions en situation de blocage à l'aide de l' SET DEADLOCK_PRIORITYinstruction. DEADLOCK_PRIORITY peut être défini sur LOW, NORMAL ou HIGH, ou peut être défini sur n'importe quelle valeur entière de la plage (-10 à 10).

Q2. Si j'exécute la sélection avec un indice NOLOCK, est-ce que cela résoudra le problème?

Non, pour plusieurs raisons:

Q3. Je soupçonne qu'un champ datetime qui est vérifié dans le cadre de la clause WHERE dans l'instruction select provoque le temps de recherche lent. Puis-je créer un index basé sur ce champ? Est-ce conseillé?

Probablement. La cause de l'impasse est presque très probablement une base de données mal indexée. Les requêtes de 10 minutes sont acceptables dans des conditions si restreintes, que je suis sûr à 100% dans votre cas n'est pas acceptable.

Avec une confiance de 99%, je déclare que votre impasse est bloquée par une analyse de table volumineuse en conflit avec les mises à jour. Commencez par capturer le graphique de blocage pour analyser la cause. Vous devrez très probablement optimiser le schéma de votre base de données. Avant d'effectuer toute modification, lisez cette rubrique Conception d'index et les sous-articles.

Remus Rusanu
la source
Merci pour votre réponse approfondie. Je suppose que j'ai encore une question. Pourquoi aurais-je la situation de blocage uniquement dans un environnement et pas dans un autre. Même si le logiciel est le même. Votre réponse suggère que la durée d'exécution de la requête Select ne fait aucune différence et c'est le fait que c'est une requête Select en soi qui provoque l'échec du processus. Mais alors, pourquoi seulement lorsque la requête de sélection prend beaucoup de temps à s'exécuter?
Elliott
4
La longueur de la requête ne fait aucune différence dans le choix de la victime du blocage . Cela fait une différence en provoquant le blocage par au moins deux facteurs: 1) des probabilités simples. Plus la requête est longue, plus il est probable que les mises à jour simultanées se chevauchent et se heurtent à des blocages. 2) une table plus grande peut utiliser un plan de requête complètement différent, susceptible de se bloquer.
Remus Rusanu
12

Voici comment ce problème particulier de blocage s'est réellement produit et comment il a été résolu. Il s'agit d'une base de données assez active avec 130K transactions effectuées quotidiennement. Les index des tables de cette base de données étaient à l'origine groupés. Le client nous a demandé de rendre les index non clusterisés. Dès que nous l'avons fait, l'impasse a commencé. Lorsque nous avons rétabli les index en cluster, le blocage s'est arrêté.

Elliott
la source
34
Quelqu'un peut-il expliquer pourquoi? (Les solutions magiques ne sont pas très utiles)
OGrandeDiEnne
1
Ce gars l'explique dans son post: mssqltips.com/sqlservertip/2517/…
siga0984
6

Les réponses ici valent la peine d'être essayées, mais vous devriez également revoir votre code. Plus précisément, lisez la réponse de Polyfun ici: Comment se débarrasser de l'impasse dans une application SQL Server 2005 et C #?

Il explique le problème de la concurrence, et comment l'utilisation de "with (updlock)" dans vos requêtes peut corriger votre situation de blocage - en fonction vraiment de ce que fait exactement votre code. Si votre code suit ce modèle, c'est probablement une meilleure solution à apporter, avant de recourir à des lectures sales, etc.

Peter Barton
la source