OVH Cloud OVH Cloud

Dead lock sur delete puis insert

3 réponses
Avatar
Fabrice Fauconnier
Bonjour,

J'ai un souci dans une application qui fait des imports en masse. Dans
certains cas, j'obtiens le message suivant :

[Microsoft][ODBC SQL Server Driver][SQL Server]La transaction (ID du
processus 61) a été bloquée sur les ressources lock par un autre processus
et a été choisie comme victime. Relancez la transaction

Cela semble complètement aléatoire. Cependant, cela n'arrive que sur des
volumes assez important, jamais unitairement. La particularité de cet import
est de faire un DELETE des données qu'il va insérer par la suite (la raison
étant qu'on n'importe pas forcément exactement les mêmes choses, donc on
nettoie d'abord). Mais la table comporte plusieurs centaines de milliers
d'enregistrements (voire millions). Je me demande si le problème ne
viendrait pas de là, SQL Server me rendrait la main alors que son DELETE
n'est pas totalement achevé en acceptant l'INSERT sur la même table.

Qu'en pensez-vous ? Est-ce que cela peut venir de là ?.Y-a-t-il un moyen de
contrôler ça ou faut-il faire des insert/update et purger le reste en fin de
traitement ?

Merci

Fabrice

3 réponses

Avatar
Laurent Marzouk [MS]
Bonjour,

En général, les instructions exécutées par un même client sont exécutées de
manière sérialisée, donc il est peut probable que le problème vienne de là,
à moins que l'application n'ait ouvert plusieurs connexions, auquel cas
l'exécution simultannée de ces 2 instructions peut effectivement générer un
deadlock si elles travaillent sur des pages de données communes.

Il faut donc tout d'abord identifier le processus qui provoque un deadlock
avec votre traitement : s'agit-il de votre propre traitement (self-deadlock)
ou d'un autre procesus ?

Pour le savoir, vous pouvez positionner les flag 1204 et 1205 (option -T <N°
flag>) dans les paramètres de démarrage de SQL Server), qui inscriront
plusieurs informations intéressantes lorsqu'un prochain deadlock se
produira. Vous aurez notamment les N° des processus entrant en conflit et
surtout les instructions SQL correspondantes, ce qui vous permttra de
vérifier votre assertion.

Si vous avez besoin de supprimer toutes les données de la table avant
d'insérer les nouvelles, il vaut mieux cependant utiliser l'instruction
TRUNCATE TABLE, qui supprime toutes les lignes de la table presque
instantanément car l'opération n'est par journalisée.

Si vous ne devez supprimer qu'une partie des lignes, vous pouvez essayer de
sortir les instructions DELETE / INSERT de la transaction si elle en
faisaient partie. Autre voie à explorer, si l'application accède à la base
par le biais de composants COM+ dans MTS, le mode d'isolation des
transactions est de facto positionné à SERIALIZABLE (i.e. le plus au niveau
d'isolation), ce qui peut parfois poser ce genre de problème. Il suffit dans
ce cas de créer une procédure stockée qui réalisera le traitement de
suppression / insertion et dans laquelle vous pourrez forcer le mode
d'isolation par défaut de SQL Server (READ COMMITTED) afin de limiter la
contention liée aux verrous:

SET TRANSACTION ISOLATION LEVEL READ COMMITTED

Vous pouvez également vérifiez que l'instruction DELETE ne pose pas de
verrous exclusif de type table (TABLOCKX ) en raison d'un nombre important
de lignes à supprimer. Si tel est le cas, vous pouvez soit essayer de
limiter la pose des verrous au niveau page (DELETE FROM <table> WITH
(PAGLOCK) WHERE ..., soit supprimer les lignes par lot de 10000 pour limiter
les verrsou posés et accélérer les traitement de suppression (plus petites
transactions). Il est également possible par ce biais de définir le niveau
d'isolation de l'instruction (ex. DELETE FROM <table> WITH (READCOMMITTED)).

Pour finir, je vous engage à parrcourir la section intitulée
"Troubleshooting Deadlocks" de l'aide en ligne SQL Server qui fournit des
instructions pour déterminer l'origine d'un deadlock.

Cordialement,

----------------------------------------------------------------
Laurent Marzouk
Microsoft Services France
----------------------------------------------------------------
SQL Server 2005 Rocks !! :-)


"Fabrice Fauconnier" wrote in message
news:433cf0cc$0$17061$
Bonjour,

J'ai un souci dans une application qui fait des imports en masse. Dans
certains cas, j'obtiens le message suivant :

[Microsoft][ODBC SQL Server Driver][SQL Server]La transaction (ID du
processus 61) a été bloquée sur les ressources lock par un autre processus
et a été choisie comme victime. Relancez la transaction

Cela semble complètement aléatoire. Cependant, cela n'arrive que sur des
volumes assez important, jamais unitairement. La particularité de cet import
est de faire un DELETE des données qu'il va insérer par la suite (la raison
étant qu'on n'importe pas forcément exactement les mêmes choses, donc on
nettoie d'abord). Mais la table comporte plusieurs centaines de milliers
d'enregistrements (voire millions). Je me demande si le problème ne
viendrait pas de là, SQL Server me rendrait la main alors que son DELETE
n'est pas totalement achevé en acceptant l'INSERT sur la même table.

Qu'en pensez-vous ? Est-ce que cela peut venir de là ?.Y-a-t-il un moyen de
contrôler ça ou faut-il faire des insert/update et purger le reste en fin de
traitement ?

Merci

Fabrice
Avatar
Fabrice Fauconnier
Bonjour

Merci pour toutes ces pistes qui nous ont beaucoup écaliré ! Du coup, nous
avons approfondi l'analyse concernant la parallélisation ou serialisation
des requêtes. Le problème est donc devenu un tout petit plus complexe mais
bien plus clair.

En fait, l'import de données a bien été fait sur une seule et unique
connexion. Nous avons bien vérifié tout ça, corrigé certaines bricoles mais
le problème persistait, certes moins fréquemment. Il s'avère qu'en fin
d'import, un traitement de recalcul ré-utilise ces données qui peuvent
évoluer au gré du recalcul et sont donc ré-injectées de la même manière par
ce deuxième thread de recalcul. Le problème vient donc bien d'une
parallélisation des requêtes. Le seul truc qui m'embête est qu'au moment du
deadlock, ce sont bien les mêmes tables qui sont attéquées mais sur des
plages de données complètement différentes. (en gros on importe les données
sur un dossier client particulier et le recalcul se fait sur un autre
dossier, les SELECT sont donc différents) Après lecture de l'aide, il
semblerait que dans certains cas, SQL Server pose un verrou exlusif pour
étendre ses pages d'index (IX) ce qui bloquerait les autres processus.
Partant de ce principe, nous avons essayé d'effectuer des DELETE unitaires
(enregistrement par enregistrement) pour limiter les concurrences.
Effectivement plus d'erreur mais j'ai peur que ce soit que reculer pour
mieux s'écraser plus tard sans compter des temps de traiement qui risque
fort de grimper.

Ce comportement est-il normal et existe-t-il un moyen de le contourner ?
J'ai bien pensé à faire des DELETE NOLOCK mais j'ai là aussi un peu peur des
effets de bord. Nous allons revoir toutes les procédures de façon à plutôt
faire de l'UPDATE/INSERT mais j'aimerai bien coprendre et éviter de retomber
dans ce genre de problème.

En tout cas, merci pour votre aide préciesue !

Fabrice
Avatar
Fred BROUARD
Bonjour,


Fabrice Fauconnier a écrit:
Bonjour

Merci pour toutes ces pistes qui nous ont beaucoup écaliré ! Du coup, nous
avons approfondi l'analyse concernant la parallélisation ou serialisation
des requêtes. Le problème est donc devenu un tout petit plus complexe mais
bien plus clair.

En fait, l'import de données a bien été fait sur une seule et unique
connexion. Nous avons bien vérifié tout ça, corrigé certaines bricoles mais
le problème persistait, certes moins fréquemment. Il s'avère qu'en fin
d'import, un traitement de recalcul ré-utilise ces données qui peuvent
évoluer au gré du recalcul et sont donc ré-injectées de la même manière par
ce deuxième thread de recalcul. Le problème vient donc bien d'une
parallélisation des requêtes. Le seul truc qui m'embête est qu'au moment du
deadlock, ce sont bien les mêmes tables qui sont attéquées mais sur des
plages de données complètement différentes. (en gros on importe les données
sur un dossier client particulier et le recalcul se fait sur un autre
dossier, les SELECT sont donc différents) Après lecture de l'aide, il
semblerait que dans certains cas, SQL Server pose un verrou exlusif pour
étendre ses pages d'index (IX) ce qui bloquerait les autres processus.
Partant de ce principe, nous avons essayé d'effectuer des DELETE unitaires
(enregistrement par enregistrement) pour limiter les concurrences.
Effectivement plus d'erreur mais j'ai peur que ce soit que reculer pour
mieux s'écraser plus tard sans compter des temps de traiement qui risque
fort de grimper.

Ce comportement est-il normal et existe-t-il un moyen de le contourner ?
J'ai bien pensé à faire des DELETE NOLOCK mais j'ai là aussi un peu peur des
effets de bord. Nous allons revoir toutes les procédures de façon à plutôt
faire de l'UPDATE/INSERT mais j'aimerai bien coprendre et éviter de retomber
dans ce genre de problème.



Non, n'utilisez pas de DELETE en NOLOCK. Pensez plutôt à baisser le niveau
d'isolation de vos transactions ou bien de faire des delete par block
représentant une page du cluster.
Pour ma part dans ce cas je ferais de multiples transactions en calculant que le
volume des MAJ ne touche pas plus d'une à 8 pages de données (a mesurer).
Vous pouvez aussi obliger certains index à vérouiller plutôt en row ou page à
l'aide de sp_indexoption.
Enfin si le batch est en dehors des heures de prod, pensez à supprimer tous les
index et les recréer en fin de traitement.
Dans tous les cas faîtes des tests !!!

A +


En tout cas, merci pour votre aide préciesue !

Fabrice





--
Frédéric BROUARD, MVP SQL Server, expert bases de données et langage SQL
Le site sur le langage SQL et les SGBDR : http://sqlpro.developpez.com
Audit, conseil, expertise, formation, modélisation, tuning, optimisation
********************* http://www.datasapiens.com ***********************