web-dev-qa-db-fra.com

L'insertion de données dans SQL Server verrouille-t-elle la totalité de la table?

J'utilise Entity Framework et j'insère dans notre base de données des enregistrements qui incluent un champ blob. Le champ blob peut contenir jusqu'à 5 Mo de données.

Lorsque vous insérez un enregistrement dans cette table, verrouille-t-il toute la table?

Donc, si vous interrogez des données de la table, sera-t-il bloqué jusqu'à ce que l'insertion soit terminée (je me rends compte que cela peut être fait, mais je parle par défaut)?

Combien de temps cela prendra-t-il avant que cela ne provoque une impasse? Ce temps dépendra-t-il de la charge sur le serveur, par exemple. S'il n'y a pas beaucoup de charge, faudra-t-il plus de temps pour provoquer une impasse?

Existe-t-il un moyen de surveiller et de voir ce qui est verrouillé à un moment donné?

Si chaque thread effectue des requêtes sur des tables uniques, existe-t-il un cas où un blocage peut se produire? Ainsi, le blocage ne peut-il se produire que si vous avez une requête qui a une jointure et agit sur plusieurs tables?

Cela tient compte du fait que la plupart de mon code est juste un groupe d’énoncés sélectionnés, pas des tas de transactions de longue durée ou quelque chose du genre.

47
peter

Sainte vache, vous avez beaucoup de questions ici, hein. Voici quelques réponses:

Lorsque vous insérez un enregistrement dans cette table, verrouille-t-il la totalité de la table?

Pas par défaut, mais si vous utilisez l'indicateur TABLOCK ou si vous effectuez certains types d'opérations de chargement en bloc, alors oui.

Donc, si vous interrogez des données de la table, est-ce que celle-ci sera bloquée jusqu'à ce que l'insertion soit terminée (je réalise qu'il existe des moyens de contourner ce problème, mais je parle par défaut)?

Celui-ci devient un peu plus compliqué. Si quelqu'un essaie de sélectionner des données d'une page de la table que vous avez verrouillée, alors oui, vous les bloquez. Vous pouvez contourner ce problème avec des éléments tels que l'indicateur NOLOCK dans une instruction select ou en utilisant l'isolation de capture instantanée validée. Pour en savoir plus sur le fonctionnement des niveaux d’isolement, consultez affiche des niveaux d’isolement de Kendra Little .

Combien de temps faudra-t-il avant que cela ne provoque une impasse? Ce temps dépendra-t-il de la charge sur le serveur, par exemple. S'il n'y a pas beaucoup de charge, faudra-t-il plus de temps pour provoquer une impasse?

Les blocages ne sont pas basés sur le temps, mais sur les dépendances. Disons que nous avons cette situation:

  • La requête A détient un tas de verrous, et pour terminer sa requête, il a besoin de choses qui sont verrouillées par la requête B.
  • Query B détient également un tas de verrous, et pour terminer sa requête, il a besoin de choses qui sont verrouillées par Query A

Aucune des requêtes ne pouvant avancer (pensez à une impasse mexicaine), SQL Server appelle cela un tirage au sort, envoie la requête de quelqu'un à l'arrière, libère ses verrous et laisse l'autre requête continuer. SQL Server sélectionne la victime en fonction de celle qui sera moins coûteuse à restaurer. Si vous voulez avoir du style, vous pouvez utiliser SET DEADLOCK_PRIORITY LOW pour des requêtes particulières vers des cibles Paint sur le dos, et SQL Server les enregistrera en premier.

Existe-t-il un moyen de surveiller et de voir ce qui est verrouillé à un moment donné?

Absolument - il existe des vues de gestion dynamique (DMV) que vous pouvez interroger comme sys.dm_tran_locks, mais le moyen le plus simple consiste à utiliser sp_WhoIsActive stocké gratuit d'Adam Machanic . C'est un remplacement vraiment astucieux pour sp_who que vous pouvez appeler comme ceci:

sp_WhoIsActive @get_locks = 1

Pour chaque requête en cours d'exécution, vous obtiendrez un petit XML décrivant tous les verrous qu'elle contient. Il y a aussi une colonne de blocage, ainsi vous pouvez voir qui bloque qui. Pour interpréter les verrous en cours, vérifiez les descriptions en ligne des types de verrous dans la documentation en ligne }.

Si chaque thread effectue des requêtes sur des tables uniques, existe-t-il un cas où un blocage peut se produire? Ainsi, le blocage ne peut-il se produire que si vous avez une requête qui a une jointure et agit sur plusieurs tables?

Croyez-le ou non, une seule requête peut réellement se bloquer , et oui, les requêtes peuvent bloquer sur une seule table. Pour en savoir plus sur les impasses, consultez La difficulté avec les impasses de Jérémie Peschka .

114
Brent Ozar

Si vous avez un contrôle direct sur le code SQL, vous pouvez forcer le verrouillage au niveau de la ligne à l'aide de:

INSERT INTO MyTable(Id, BigColumn) WITH (ROWLOCK)
VALUES(...)

Ces deux réponses pourraient être utiles:

Est-il possible de forcer le verrouillage au niveau de la ligne dans SQL Server?

Verrouillage d'une table avec une sélection dans Entity Framework

Pour afficher les verrous en attente actuels dans Management Studio, recherchez sous le serveur, puis sous Management/Activity Monitor. Il a une section pour les verrous par objet, vous devriez donc pouvoir voir si les insertions posent réellement un problème.

3
Andrew Bain

Les erreurs d'interblocage reviennent généralement assez rapidement. Les états d'interblocage ne se produisent pas à la suite d'une erreur de dépassement de délai pendant l'attente d'un verrouillage Le blocage est détecté par SQL Server en recherchant des cycles dans les demandes de verrouillage.

0
Timothy Klenke

La meilleure réponse que je puisse trouver est: ça dépend.

Le meilleur moyen de vérifier est de trouver votre SPID de connexion et d'utiliser sp_lock SPID pour vérifier si le mode de verrouillage est X sur le type de tabulation. Vous pouvez également vérifier le nom de la table avec SELECT OBJECT_NAME(objid). J'aime aussi utiliser la requête ci-dessous pour vérifier le verrouillage.

    SELECT RESOURCE_TYPE,RESOURCE_SUBTYPE,DB_NAME(RESOURCE_DATABASE_ID) AS 'DATABASE',resource_database_id DBID,
    RESOURCE_DESCRIPTION,RESOURCE_ASSOCIATED_ENTITY_ID,REQUEST_MODE,REQUEST_SESSION_ID,
    CASE WHEN RESOURCE_TYPE = 'OBJECT' THEN OBJECT_NAME(RESOURCE_ASSOCIATED_ENTITY_ID,RESOURCE_DATABASE_ID) ELSE '' END OBJETO
    FROM SYS.DM_TRAN_LOCKS (NOLOCK)
    WHERE REQUEST_SESSION_ID = --SPID here

Dans SQL Server 2008 (et versions ultérieures), vous pouvez désactiver l'escalade de verrous sur la table et appliquer un WITH (ROWLOCK) dans votre clause d'insertion pour forcer efficacement le verrouillage de ligne. Cela ne peut pas être fait avant SQL Server 2008 (vous pouvez écrire WITH ROWLOCK, mais SQL Server peut choisir de l'ignorer).

Je parle des généraux ici et je n'ai pas beaucoup d'expérience avec les BLOB, car je conseille généralement aux développeurs de les éviter, en particulier s'ils dépassent 1 Mo.

0
Thiago Dantas