J'insérais deux ensembles de données, en utilisant une journalisation minimale, dans une table de tas vide à l'aide de deux tâches d'exécution SQL exécutées en parallèle et avec SQL de la forme suivante.
INSERT INTO Table (TABLOCK) SELECT FROM ...
Une fois le travail bloqué, l'une des tâches SQL est devenue une victime de blocage. Ci-dessous, la sortie XML du graphique de blocage.
Quelqu'un peut-il expliquer ce qui se passait sous le capot?
<resource-list>
<objectlock lockPartition="0" objid="1586156746" subresource="FULL" dbid="7" objectname="dbo.TargetTable" id="lock7374a00" mode="IX" associatedObjectId="1586156746">
<owner-list>
<owner id="process9609dc8" mode="Sch-S"/>
<owner id="process9609dc8" mode="IX"/>
</owner-list>
<waiter-list>
<waiter id="process5e13048" mode="X" requestType="convert"/>
</waiter-list>
</objectlock>
<objectlock lockPartition="0" objid="1586156746" subresource="FULL" dbid="7" objectname="dbo.TargetTable" id="lock7374a00" mode="IX" associatedObjectId="1586156746">
<owner-list>
<owner id="process5e13048" mode="Sch-S"/>
<owner id="process5e13048" mode="IX"/>
</owner-list>
<waiter-list>
<waiter id="process9609dc8" mode="X" requestType="convert"/>
</waiter-list>
</objectlock>
</resource-list>
Les choses deviennent beaucoup plus délicates car j'ai trouvé que dans la plupart des cas, les deux tâches d'exécution SQL peuvent s'exécuter en parallèle avec succès. Essayez ci-dessous:
Create table dbo.TablockInsert (c1 int, c2 int, c3 int)
--then issue the script in two Execute Sql Task in parallel you won't fail:
insert into dbo.TablockInsert(TABLOCK) SELECT 1, 1, 1
Étant donné que la seule différence est l'instruction SELECT ... FROM ..., ressemble à l'instruction SELECT ... FROM ... peut avoir un impact sur le mode de verrouillage ici?
Réponses:
Le Guide de performances de chargement des données a été écrit pour SQL Server 2008, mais pour autant que je sache, Microsoft n'a apporté aucune amélioration dans ce domaine pour les tas. Voici un devis pour votre scénario de chargement:
La partie importante est que vous n'obtenez pas de verrou BU avec
INSERT ... SELECT
. Vous obtiendrez toujours un verrou exclusif sur la table, donc un seulINSERT
peut fonctionner à la fois.Dans les commentaires, vous avez dit que vous inséreriez 100 000 lignes ou moins et que d'autres processus ne s'exécuteraient pas sur les tables lors des insertions. Lors de l'envoi de deux requêtes INSERT à la base de données, je m'attendrais à ce qu'une des trois choses se produise:
Dans tous les cas, vous bénéficiez ou n'êtes pas blessé en ajoutant un
TABLOCKX
indice à la requête, c'est donc ma recommandation de contourner l'impasse. Si vous voulez savoir pourquoi l'impasse se produit parfois, vous devrez chercher une autre réponse pour cela.Dans un scénario différent dans lequel vous avez vraiment besoin d'une insertion parallèle, deux façons de contourner le problème BU sont de partitionner votre segment et d'avoir chaque session insérée dans une partition distincte ou de charger vos données via BCP, BULK INSERT ou Integration Services .
la source
Vous vous insérez à
dbo.TargetTable
partir de deux sessions et les deux en utilisantTABLOCK
hint.Bothprocess9609dc8
etprocess5e13048
process holdingSch-S
etIX
verrous qui sont compatibles les uns avec les autres afin que les deux processus puissent tenir en même temps. Mais les deux veulent convertir leIX
verrou enExclusive X
type.X
les serrures ne sont pas compatibles entre elles. Par conséquent, SQL Server a choisi l'une des sessions comme victime de blocage au lieu d'attendre indéfiniment.Informations de base sur l'impasse.
Tableau de compatibilité des verrous (moteur de base de données).
Détection et suppression des interblocages.
la source