web-dev-qa-db-fra.com

Instructions SQL Server SELECT provoquant le blocage

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?

16
Neil Barnwell

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é).

29
Remus Rusanu

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, voir Types of Concurrency Control. Aucune autre transaction ne peut modifier les données tant que des verrous shared (S) existent sur la ressource. Les verrous Shared (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 verrous shared (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.

14
Quassnoi

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

2
David Espart

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."

http://www2.sqlblog.com/blogs/alexander_kuznetsov/archive/2009/04/10/selects-under-read-committed-and-repeatable-read-may-return-incorrect-results.aspx

0
A-K

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)
0
Senol Cakir

Vous pouvez définir le niveau de transaction sur Lecture non validée.

0
Johnno Nolan