82 votes

Diagnostiquer les blocages dans SQL Server 2005

Nous voyons certains pernicieuse, mais rare, impasse des conditions dans le Débordement de la Pile de SQL Server 2005 bases de données.

J'ai attaché le profiler, configurer une trace de profil à l'aide de cet excellent article sur la résolution des blocages, et capturé un tas d'exemples. La chose étrange est que le blocage d'écriture est toujours la même:

UPDATE [dbo].[Posts]
SET [AnswerCount] = @p1, [LastActivityDate] = @p2, [LastActivityUserId] = @p3
WHERE [Id] = @p0

L'autre blocage de déclaration varie, mais il est généralement une sorte de trivial, de la simple lecture de la table posts. Ce on obtient toujours tué dans l'impasse. Voici un exemple

SELECT
[t0].[Id], [t0].[PostTypeId], [t0].[Score], [t0].[Views], [t0].[AnswerCount], 
[t0].[AcceptedAnswerId], [t0].[IsLocked], [t0].[IsLockedEdit], [t0].[ParentId], 
[t0].[CurrentRevisionId], [t0].[FirstRevisionId], [t0].[LockedReason],
[t0].[LastActivityDate], [t0].[LastActivityUserId]
FROM [dbo].[Posts] AS [t0]
WHERE [t0].[ParentId] = @p0

Pour être parfaitement clair, on ne voit pas écrire / écrire des blocages, mais en lecture / écriture.

Nous avons un mélange de LINQ et des requêtes SQL paramétrées pour le moment. Nous avons ajouté with (nolock) de toutes les requêtes SQL. Cela peut avoir aidé certains. Nous avons également eu un seul (très) mal écrit insigne de la requête que je fixe hier, qui a été prise à la hausse de 20 secondes pour s'exécuter à chaque fois, et était en cours d'exécution, chaque minute sur le dessus de cela. J'espérais que c'était la source de certains problèmes de verrouillage!

Malheureusement, j'ai eu une autre erreur de blocage d'environ 2 heures. Même symptômes, même coupable de l'écriture.

Vraiment étrange, c'est que le verrouillage en écriture instruction SQL que vous voyez ci-dessus est d'une partie très spécifique chemin d'accès du code. C'est seulement exécutée lorsqu'une nouvelle réponse est ajouté à une question, il met à jour le parent en question avec la nouvelle réponse comte et de la dernière date/de l'utilisateur. C'est, évidemment, pas que la commune par rapport au nombre imposant de lectures que nous faisons! Aussi loin que je peux dire, nous ne faisons pas de grands nombres d'écrit n'importe où dans l'application.

Je me rends compte que NOLOCK est une sorte de marteau géant, mais la plupart des requêtes, nous courons ici n'ont pas besoin d'être précis. Allez-vous les soins si votre profil d'utilisateur est à quelques secondes de la date?

À l'aide de NOLOCK avec Linq est un peu plus difficile, car Scott, Hanselman discute ici.

Nous sommes en train de flirter avec l'idée de l'utiliser

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

sur la base de la base de données de contexte, de sorte que tous nos requêtes LINQ ont ce jeu. Sans cela, nous aurions à envelopper chaque LINQ appel que nous faisons (ainsi, la simple lecture, ce qui est la grande majorité d'entre eux) dans un 3-4 ligne de transaction de bloc de code, ce qui est laid.

Je suppose que je suis un peu frustré que trivial lit dans SQL 2005 impasse sur l'écrit. J'ai pu voir écrire/écrire des blocages d'être un énorme problème, mais lit? Nous ne sommes pas de l'exécution d'un site bancaire ici, nous n'avons pas besoin d'une exactitude parfaite à chaque fois.

Des idées? Pensées?


Êtes-vous de l'instanciation d'un LINQ to SQL DataContext de l'objet, pour chaque opération, ou vous êtes peut-être à partager le même contexte statique pour tous vos appels?

Jeremy, nous sommes le partage d'une statique datacontext dans le Contrôleur de base pour la plupart:

private DBContext _db;
/// <summary>
/// Gets the DataContext to be used by a Request's controllers.
/// </summary>
public DBContext DB
{
    get
    {
        if (_db == null)
        {
            _db = new DBContext() { SessionName = GetType().Name };
            //_db.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
        }
        return _db;
    }
}

Recommandez-vous de nous créer un nouveau contexte pour chaque Contrôleur, ou par Page, ou .. plus souvent?

44voto

Geoff Dalgas Points 2023

Selon MSDN:

http://msdn.microsoft.com/en-us/library/ms191242.aspx

Lorsque l' READ committed ou PERMETTRE l'ISOLEMENT d'INSTANTANÉ de base de données les options sont SUR la logique des copies (versions) sont maintenues pour toutes les données modifications effectuées dans l' la base de données. Chaque fois qu'une ligne est modifiée par une transaction spécifique, la instance du Moteur de Base de données stocke une version de la commis auparavant l'image de la ligne dans la base de données tempdb. Chaque version est marquée avec la transaction numéro de séquence de la transaction que fait le changement. Les versions de lignes modifiées sont enchaînés à l'aide d'un lien liste. La dernière ligne de la valeur est toujours stockées dans la base de données actuelle et enchaîné à la version de lignes stockées dans la base de données tempdb.

Pour les transactions de courte durée, un version d'une ligne modifiée peut obtenir mis en cache dans le pool de mémoire tampon sans l'obtention écrites dans les fichiers de disque de la base de données tempdb. Si le besoin de la version ligne est de courte durée, il obtiendrez simplement abandonné à partir de la de pool de mémoire tampon et ne sont pas nécessairement engager des I/O de frais généraux.

Il semble y avoir une légère perte de performance pour les frais généraux supplémentaires, mais il peut être négligeable. Nous devrions tester pour s'en assurer.

Essayez le réglage de cette option et de SUPPRIMER tous les NOLOCKs de code requêtes sauf si c'est vraiment nécessaire. NOLOCKs ou à l'aide de méthodes globales dans le contexte de base de données gestionnaire de lutte contre la base de données de niveaux d'isolation de transaction sont des pansements pour le problème. NOLOCKS masque problèmes fondamentaux de notre couche de données et, éventuellement, conduire à la sélection des données peu fiables, où automatique sélectionner / mettre à jour les versions de ligne semble être la solution.

ALTER Database [StackOverflow.Beta] SET READ_COMMITTED_SNAPSHOT ON

37voto

JEzell Points 351

NOLOCK et READ UNCOMMITTED sont une pente glissante. Vous devriez ne jamais les utiliser, sauf si vous comprenez pourquoi l'impasse qui se passe en premier. Il serait de m'inquiéter de ce que vous dites, "Nous avons ajouté avec (nolock) pour toutes les requêtes SQL". Avoir besoin d'ajouter AVEC NOLOCK partout, c'est un signe certain que vous avez des problèmes dans votre couche de données.

La mise à jour de l'énoncé lui-même semble un peu problématique. Avez-vous déterminer le nombre plus tôt dans la transaction, ou juste de le tirer à partir d'un objet? AnswerCount = AnswerCount+1 lorsqu'une question est ajouté est probablement une meilleure façon de gérer cela. Alors vous n'avez pas besoin d'une transaction pour obtenir le nombre correct et vous n'avez pas à vous soucier du problème de concurrence que vous êtes potentiellement s'exposer soi-même.

Un moyen facile d'obtenir autour de ce type de blocage question sans beaucoup de travail et sans activation sale lit est d'utiliser "Snapshot Isolation Mode" (nouveau dans SQL 2005) qui vous donnera toujours une lecture propre de la dernière non modifiée de données. Vous pouvez également attraper et de réessayer de l'impasse des déclarations assez facilement si vous souhaitez les gérer correctement.

25voto

MrB Points 2047

L'OP question est de se demander pourquoi ce problème s'est produit. Ce post vise à répondre que, tout en laissant des solutions possibles à être travaillé par d'autres.

C'est probablement un indice lié à la question de. Par exemple, disons que le tableau des Postes a un index non-cluster X, qui contient le ParentID et un (ou plus) de la / des champ(s) d'être mis à jour (AnswerCount, LastActivityDate, LastActivityUserId).

Un blocage peut se produire si les SÉLECTIONNER cmd ne partage verrou de lecture sur l'indice de X pour effectuer une recherche par le ParentId et puis il faut faire partagé un verrou en lecture sur l'index cluster pour obtenir le reste des colonnes alors que la mise à JOUR cmd ne une écriture verrou exclusif sur l'index cluster et la nécessité d'obtenir une réduction de verrou exclusif sur l'index X de le mettre à jour.

Vous avez maintenant une situation où Un blocage de l'X et essayer d'obtenir un Y alors que B verrouillé Y et essaie d'obtenir de X.

Bien sûr, nous aurons besoin de l'OP pour mettre à jour son post avec plus d'informations concernant les index sont en jeu pour confirmer si c'est réellement la cause.

18voto

Leon Bambrick Points 10886

Je suis assez mal à l'aise à propos de cette question et de la surveillance des réponses. Il y a beaucoup de "essayer cette poudre magique! Pas que la magie de la poussière!"

Je ne peux pas voir n'importe où que vous avez anaylzed les verrous qui sont prises, et de déterminer quel type exact de serrures sont dans l'impasse.

Tout ce que vous avez indiqué, c'est que certains verrous-pas ce qui est de l'interblocage.

Dans SQL 2005, vous pouvez obtenir plus d'informations sur ce que les verrous sont en train d'être prises par l'aide de:

DBCC TRACEON (1222, -1)

de sorte que lorsque le blocage se produit, vous aurez de meilleurs diagnostics.

14voto

jeremcc Points 3720

Sont vous instancier une nouvelle LINQ to SQL DataContext objet pour chaque opération ou êtes-vous peut-être partage le même contexte statique pour tous vos appels ? J’ai essayé initialement cette dernière approche, et de ce que je retiens, il fait verrouillage indésirable dans la BD. Maintenant, j’ai créer un nouveau contexte pour chaque opération atomique.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X