Nous utilisons une base de données SQL Server 2005 (sans version de ligne) avec une instruction select énorme et nous constatons qu'elle bloque l'exécution d'autres instructions (vue à l'aide de sp_who2
). Je ne savais pas que les instructions SELECT pouvaient provoquer un blocage - puis-je faire quelque chose pour atténuer cela?
SELECT peut bloquer les mises à jour. Un modèle de données et une requête correctement conçus ne provoqueront qu'un blocage minimal et ne constitueront pas un problème. Le conseil «habituel» AVEC NOLOCK est presque toujours la mauvaise réponse. La bonne réponse est d’ajuster votre requête afin qu’elle n’analyse pas d’énormes tables.
Si la requête ne peut pas être syntonisée, vous devez d'abord considérer le niveau SNAPSHOT ISOLATION , puis envisager d'utiliser DATABASE SNAPSHOTS et la dernière option doit être DIRTY READS (et il est préférable de modifier le niveau d'isolation plutôt que que d’utiliser le CONSEIL NOLOCK). Notez que les lectures modifiées, comme le nom l'indique clairement, renverront des données incohérentes (par exemple, le nombre total de pages peut être déséquilibré).
De documentation :
Les verrous
Shared (S)
permettent aux transactions simultanées de lire(SELECT)
une ressource sous un contrôle pessimiste de la simultanéité. Pour plus d'informations, voirTypes of Concurrency Control
. Aucune autre transaction ne peut modifier les données tant que des verrousshared (S)
existent sur la ressource. Les verrousShared (S)
sur une ressource sont libérés dès que l'opération de lecture est terminée, à moins que le niveau d'isolation de la transaction ne soit défini sur lecture ou supérieure, ou qu'un indice de verrouillage soit utilisé pour conserver les verrousshared (S)
pendant la durée de la transaction.
Un shared lock
est compatible avec un autre verrou partagé ou un verrou de mise à jour, mais pas avec un verrou exclusif.
Cela signifie que vos requêtes SELECT
bloqueront les requêtes UPDATE
et INSERT
et vice versa.
Une requête SELECT
placera un verrou partagé temporaire lorsqu'elle lira un bloc de valeurs dans la table et le supprimera une fois la lecture terminée.
Pendant le temps où le verrou existe, vous ne pourrez rien faire des données dans la zone verrouillée.
Deux requêtes SELECT
ne se bloqueront jamais (sauf si elles sont SELECT FOR UPDATE
)
Vous pouvez activer le niveau d'isolement SNAPSHOT
sur votre base de données et l'utiliser, mais notez que cela n'empêchera pas les requêtes UPDATE
d'être verrouillées par des requêtes SELECT
(ce qui semble être votre cas).
Cela évitera toutefois que les requêtes SELECT
soient bloquées par UPDATE
.
Notez également que SQL Server
, contrairement à Oracle
, utilise le gestionnaire de verrous et le maintient verrouillé dans une liste liée en mémoire.
Cela signifie que sous une charge importante, le simple fait de placer et de supprimer un verrou peut être lent, car la liste liée doit elle-même être verrouillée par le fil de la transaction.
Pour effectuer des lectures sales, vous pouvez soit:
using (new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions {
IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
//Your code here
}
ou
SelectCommand = "SELECT * FROM Table1 WITH (NOLOCK) INNER JOIN Table2 WITH (NOLOCK) ..."
n'oubliez pas que vous devez écrire WITH (NOLOCK) après chaque table que vous voulez lire en lecture
Vous pourriez aussi avoir des impasses:
"blocages impliquant une seule table" http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/01/01/reproducing-deadlocks-involving-only-one-table.aspx
et ou résultats incorrects:
"Les sélections sous READ COMMITTED et REPEATABLE READ peuvent renvoyer des résultats incorrects."
Vous pouvez utiliser l'indicateur de table WITH(READPAST)
. C'est différent de la WITH(NOLOCK)
. Il obtiendra les données avant le début de la transaction et ne bloquera personne. Imaginez que vous avez exécuté l'instruction avant le début de la transaction.
SELECT * FROM table1 WITH (READPAST)
Vous pouvez définir le niveau de transaction sur Lecture non validée.